forked from troll-model/TROLL
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain_v2.3.2.cpp
More file actions
3428 lines (2803 loc) · 150 KB
/
Copy pathmain_v2.3.2.cpp
File metadata and controls
3428 lines (2803 loc) · 150 KB
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
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*####################################################################
### TROLL
### Individual-based forest dynamics simulator
### Version 1: Jerome Chave
### Version 2.1 & 2.2: Isabelle Marechaux & Jerome Chave
### Version 2.3 onwards: Isabelle Marechaux, Fabian Fischer, Jerome Chave
###
### History:
### version 0.1 --- JC - 22 Sep 97
### version 0.2 --- JC - 06 Oct 97
### version 0.3 --- JC - 11-14 Nov 97
### version 1.0 --- JC - stable version Chave, Ecological Modelling (1999)
### version 1.1 --- JC - 02-30 Sep 98
### version 1.2 --- JC - 22 Jan 00
### version 1.3 --- JC - 28 Sep 01 stable version Chave, American Naturalist (2001)
###
### version 2.0 --- JC - 23 Mar 11 (physiology-based version, translation of comments into English)
### version 2.01 --- IM - oct-nov 13
### version 2.02 --- IM - apr-may 2015
### version 2.03 --- IM - jul 2015
### version 2.04 --- IM - jul 2015 (monthly timestep)
### version 2.1 --- IM - dec 2015 (undef/defined alternative versions)
### version 2.11 --- IM - jan 2016 timestep better used
### version 2.12 --- JC - jan 2016 porting to GitHub for social coding, check of the MPI routines and update, new header for code, trivia: reindentation (orphan lines removed)
### version 2.2 --- IM - may 2016 core changes in: daily coupling with environment; respiration; treefall module; leaf pool dynamics
### version 2.3 --- FF - oct-nov 2016: bug fixing (including UpdateSeed() bug), general reworking of code, changes in CalcLAI(), initialisation from data, toolbox with alternative fine flux calculation (cf. end of script)
### version 2.3.0 --- IM & JC - janv-feb 2017: new tree size threshold to maturity (dbhmature), changes in input file structure, corrections of temperature dependencies in GPPleaf. Code acceleration (use of lookup tables instead of functions in the calculations of the Fluxh() and GPPleaf() routines; faster whole-tree GPP calculation. This results in an increase in speed of a factor 4.
### version 2.3.1 --- IM & JC - feb-mar 2017: introduces the dispersal cell, or dcell concept (square subplot of linear size length_dcell)
### code acceleration FASTGPP concept improved.
### DCELL: GNU scientific library is needed -- on osx, type "brew install gsl"
### DCELL: Compile command (osx/linux):
### g++ -O3 -Wall -o troll main_xx.cpp -lgsl -lgslcblas -lm
### DCELL: Code profiling (unix): g++ -O3 -Wall -o troll main_xx.cpp -lgsl -lgslcblas -lm -g -pg
###
####################################################################*/
/*
Glossary: MPI = Message Passing Interface. Software for sharing information
across processors in parallel computers. If global variable MPI is not defined,
TROLL functions on one processor only.
*/
#undef MPI /* If flag MPI defined, parallel routines (MPI software) are switched on */
#undef easyMPI /* If flag easyMPI defined, parallel routine for fast search of parameter space are switched on */
#undef toolbox /* never to be defined! Toolbox is an assortment of alternative formulations of TROLL procedures, attached to the code */
#undef DCELL // this explores the need for an intermediate grid cell size
/* Libraries */
# include <cstdio>
# include <iostream>
# include <fstream>
# include <cstdlib>
# include <string>
# include <limits>
# include <ctime>
# include <cmath>
# ifdef MPI
# include "mpi.h"
# endif
# ifdef easyMPI
# include "mpi.h"
# endif
using namespace std;
/* Global constants (e.g. PI and various derivatives...) */
# define PI 3.141592654
# define twoPi 6.2831853071
# define Pis2 1.570796327
# define iPi 0.3183099
char buffer[256], inputfile[256], outputinfo[256], inputfile_data[256], *bufi(0), *buf(0), *bufi_data(0);
/* random number generators */
double genrand2(void);
void sgenrand2(unsigned long);
unsigned long genrand2i(void);
void sgenrand2i(unsigned long);
/* file output streams */
fstream out,out2;
fstream output[38];
/****************/
/* User control */
/****************/
/* options can be turned on (1) or off (0). This comes, however, at computational costs. Where routines have to be called frequently, if-conditioning should be done as far outside the loop as possible (e.g. for DAILYLIGHT outside voxel loops) */
/* currenly, options are set below, but inclusion in parameter sheet needed (for control from R) */
bool
_FASTGPP=0, /* This defines an option to compute only GPP from the topmost value of PPFD and GPP, instead of looping within the crown. Much faster and more accurate */
_BASICTREEFALL=1, /* if defined: treefall is a source of tree death (and if TREEFALL not defined, this is modeled through simple comparison between tree height and a threshold t_Ct, if not defined, treefall is not represented as a separated and independent source of death, but instead, all tree death are due to the deathrate value) */
_TREEFALL=0, /* computation of the force field if TREEFALL is defined, neighboring trees contribute to fell each tree */
_DAILYLIGHT=1, /* if defined: the rate of carbon assimilation integrates an average daily fluctuation of light (thanks to GPPDaily). Should be defined to ensure an appropriate use of Farquhar model */
_SEEDTRADEOFF=0, /* if defined: the number of seeds produced by each tree is determined by the tree NPP allocated to reproduction and the species seed mass, otherwise the number of seeds is fixed; besides, seedling recruitment in one site is not made by randomly and 'equiprobably' picking one species among the seeds present at that site but the probability of recruitment among the present seeds is proportional to the number of seeds (in s_Seed[site]) time the seed mass of each species */
_NDD=1, /* if defined, negative density dependant processes affect both the probability of seedling recruitment and the local tree death rate. The term of density-dependance is computed as the sum of conspecific tree basal area divided by their distance to the focal tree within a neighbourhood (circle of radius 15m) */
_OUTPUT_reduced=1, /* reduced set of ouput files */
_OUTPUT_last100=0, /* output that tracks the last 100 years of the simulation for the whole grid (2D) */
_OUTPUT_fullLAI=0, /* output of full final voxel field */
_FromData=0; /* if defined, an additional input file can be provided to start simulations from an existing data set or a simulated data set (5 parameters are needed: x and y coordinates, dbh, species_label, species */
/********************************/
/* Parameters of the simulation */
/********************************/
int sites, /* number of sites */
cols, /* nb of columns */
rows, /* nb of lines */
numesp, /* nb of species */
iterperyear, /* nb of iter in a year (=12 if monthly timestep, =365 if daily timestep) */
nbiter, /* total nb of timesteps */
iter, /* current timestep */
nbout, /* nb of outputs */
freqout; /* frequency HDF outputs */
#ifdef DCELL
gsl_rng *gslrand;
int length_dcell, /* v2.3.1 linear size of a dcell */
linear_nb_dcells, /* linear number of dcells note that nbdcells = linear_nb_dcells^2 */
sites_per_dcell, /* number of sites per dcell */
nbdcells; /* total number of dcells */
int **MAP_DCELL(0); /* list of sites per dcell (for fast fillin) */
double *prior_DCELL(0); /* prior for picking the dispersal sites within the dcell -- vector of size sites_per_dcell and with all entries equal to 1/sites_per_dcell (because the dispersal is equiprobable) */
unsigned int *post_DCELL(0); /* number of seeds per site within the dcell */
double *prior_GERM(0); /* prior for picking the germination event within a site -- vector of size numesp and with entries equal to the number of seeds multiplied by seedsize */
unsigned int *post_GERM(0); /* vector with only one non-null entry (the successful germination event) */
#endif
int HEIGHT, /* max height (in m) */
dbhmaxincm, /* max DBH times 100 (ie dbh in cm *100 = in meters) */
RMAX, /* max crown radius */
SBORD; /* RMAX*cols */
float NV, /* nb cells per m (vertical) */
NH, /* nb cells per m (horizontal) */
LV, /* LV = 1.0/NV */
LH, /* LH = 1.0/NH */
timestep; /* duration of one timestep (in years)=1/iterperyear */
float p_nonvert, /* ratio of non-vertical incident light */
Cseedrain, /* constant used to scale total seed rain per hectare across species */
nbs0, /* nb of seeds produced and dispersed by each mature tree when SEEDTRADEOFF is not defined */
Cair, /* atmosphericCO2 concentration, if we aim at making CO2 vary (scenarios), CO2 will have to have the same status as other climatic variables */
iCair; /* inverse of Cair */
/* new version 2.2 */
float daily_light[24]; /* normalized (ie between 0 and 1) daily light variation (used if DAILYLIGHT defined) */
float daily_vpd[24]; /* normalized (ie between 0 and 1) daily vpd variation (used if DAILYLIGHT defined) */
float daily_T[24]; /* normalized (ie between 0 and 1) daily T variation (used if DAILYLIGHTdefined) */
/*parameter for NDD*/
float R, /* distance beyond which NDD effect is not accounted anymore*/
deltaR, /* NDD strength parameter in recruitment */
deltaD, /* NDD strength parameter in deathrate */
BAtot;
/*********************************************/
/* Environmental variables of the simulation */
/*********************************************/
/* Climate input data */
/* these climate input data are given in the input file, its structure depends on the timestep and scenario used for the simulation */
/* new version 2.2 */
float *Temperature(0); /* in degree Celsius */
float *DailyMaxTemperature(0); /* in degree Celsius */
float *NightTemperature(0); /* in degree Celsius */
float *Rainfall(0); /* in mm */
float *WindSpeed(0); /* in m/s */
float *MaxIrradiance(0); /* in W/m2 */
float *MeanIrradiance(0); /* in W/m2 */
float *SaturatedVapourPressure(0); /* in kPa */
float *VapourPressure(0); /* in kPa */
float *VapourPressureDeficit(0); /* in kPa */
float *DailyVapourPressureDeficit(0); /* in kPa */
float *DailyMaxVapourPressureDeficit(0); /* in kPa */
/* New in v.2.3.0 */
int nbTbins; /*nb of bins for the temperature lookup tables */
float iTaccuracy; /* inverse of accuracy of a temperature bin (e.g. Taccuracy us 0.1 or 0.5 °C, so iTaccuracy is 10.0 or 2.0, resp) */
float *LookUp_KmT(0); /* lookup table for fast comput of Farquhar as a function of T */
/* !! leaf temperature must be comprised between 0°C and 60°C
(T_leaf is stored every 0.5°C, so 120 values in total */
float *LookUp_GammaT(0); /* lookup table for fast comput of Farquhar */
float *LookUp_tempRday(0); /* lookup table for fast comput of Farquhar */
float *LookUp_VcmaxT(0); /* lookup table for fast comput of Farquhar */
float *LookUp_JmaxT(0); /* lookup table for fast comput of Farquhar */
float *LookUp_flux(0); /* lookup table for faster computation of PPFD*/
float *LookUp_VPD(0); /* lookup table for faster computation of VPD */
float *LookUp_T(0); /* lookup table for faster computation of T */
float *LookUp_Rstem(0); /* lookup table for faster computation of Rstem */
float *LookUp_Rnight(0); /* lookup table for faster computation of Rstem */
/***** Environmental variables, changed at each timestep *****/
float temp, /* Temperature */
tmax, /* Daily max temperature */
tnight, /* Night mean temperature */
precip, /* Rainfall */
WS, /* WindSpeed */
Wmax, /* Daily max irradiance (average for timestep) (in micromol PAR photon/m^2/s)*/
/* used in the photosynthesis part. see if it would not be better to have value in the right unit in the input file, however W/m2 is the common unit of meteo station */
/* below: new version 2.2 */
Wmean, /* mean irradiance (in W/m2)*/
e_s, /* SaturatedVapourPressure */
e_a, /* VapourPressure*/
VPDbasic, /* VapourPressureDeficit */
VPDday, /* DailyVapourPressureDeficit */
VPDmax; /* DailyMaxVapourPressureDeficit */
/****************************************/
/* Common variables for the species */
/* (simplifies initial version 170199) */
/****************************************/
//int Cm; /* Treefall threshold */
float klight, /* light absorption rate or extinction cefficient used in Beer-Lambert law to compute light within the canopy */
phi, /* apparent quantum yield (in micromol C/micromol photon). phi is the quantum yield multiplied by leaf absorbance (in the literature, the quantum yield is often given per absorbed light flux, so one should multiply incident PPFD by leaf absorbance, see Poorter et al American Journal of Botany (assumed to be 0.91 for tropical tree species). Even though holding phi constant across species is widely assumed, in reality, phi varies across species and environmental conditions (see eg Domingues et al 2014 Plant Ecology & Diversity) */
theta, /* parameter of the Farquhar model set to 0.7 in this version. For some authors, it should be species-dependent or temperature dependent, but these options are not implemented here */
g1, /* g1 parameter of Medlyn et al's model of stomatal conductance. v230: defined as a global parameter shared by species, instead of a Species class's variable */
alpha, /* apparent quantum yield to electron transport in mol e-/mol photons, equal to the true quantum yield multiplied by the leaf absorbance -- v.2.2 */
vC, /* variance of treefall threshold */
H0, /* initial height (in m) */
DBH0, /* initial DBH (in m) */
de0, /* initial crown Crown_Depth (in m) */
de1, /* Crown_Depth/height slope */
/* fallocwood and falloccanopy new -- v.2.2 */
fallocwood, /* fraction of biomass allocated to above ground wood (branches+stem) */
falloccanopy, /* fraction of biomass allocated to canopy (leaves + reproductive organs + twigs) */
dens, /* initial leaf density (in m^2/m^3) */
ra1, /* crown radius - dbh slope */
ra0, /* initial crown radius (in m) */
m, /* basal death rate */
m1; /* deathrate-wsg slope -- new v.2.2 */
float **LAI3D(0); /* leaf density (per volume unit) */
unsigned short *Thurt[3]; /* Treefall field */
int *SPECIES_GERM (0);
float *PROB_S (0); /* _SEEDTRADEOFF */
float tempRday; /* temporary variable used for the computation of leaf day respiration -- new v.2.2 */
/***************/
/* Diagnostics */
/***************/
int nbdead_n1, /* nb deaths other than treefall dbh > 1 cm, computed at each timestep */
nbdead_n10, /* nb deaths other than treefall dbh > 10 cm, computed at each timestep */
nblivetrees, /* nb live trees for each timestep */
nbdead_c1, /* nb deaths caused by a treefall dbh > 1 cm, computed at each timestep, _BASICTREEFALL */
nbdead_c10, /* nb deaths caused by a treefall dbh > 10 cm, computed at each timestep, _BASICTREEFALL */
nbTreefall1, /* nb treefalls for each timestep (dbh > 1cm), _BASICTREEFALL */
nbTreefall10; /* nb treefalls for each timestep (dbh > 10 cm), _BASICTREEFALL */
//long int *persist; /* persistence histogram */
int *nbdbh(0); /* dbh size distribution */
float *layer(0); /* vertical LAI histogram */
/**************/
/* Processors */
/**************/
int mpi_rank,mpi_size;
int easympi_rank,easympi_size;
/******************/
/* MPI procedures */
/******************/
#ifdef MPI
unsigned short **LAIc[2];
void
MPI_ShareSeed(unsigned char **,int),
MPI_ShareField(unsigned short **,unsigned short ***,int),
MPI_ShareTreefall(unsigned short **,int);
#endif
/**********************/
/* Simulator routines */
/**********************/
void
Initialise(void),
InitialiseFromData(void),
AllocMem(void),
BirthInit(void),
Evolution(void),
UpdateField(void),
UpdateTreefall(void), // _BASICTREEFALL
UpdateTree(void),
Average(void),
OutputField(void),
FreeMem(void);
/**********************/
/** Output routines ***/
/**********************/
void
OutputSnapshot(fstream& output),
OutputSnapshotDetail(fstream& output),
OutputSpeciesParameters(fstream& output),
OutputFullLAI(fstream& output_CHM, fstream& output_LAD);
/****************************/
/* Various inline functions */
/****************************/
inline float flor(float f) {
if(f>0.) return f;
else return 0.;
}
inline float florif(int i) {
if(i>0) return float(i);
else return 0.;
}
inline float maxf(float f1, float f2) {
if(f1>f2) return f1;
else return f2;
}
inline float minf(float f1, float f2) {
if(f1<f2) return f1;
else return f2;
}
inline int min(int i1, int i2) {
if(i1<i2) return i1;
else return i2;
}
inline int max(int i1, int i2) {
if(i1>i2) return i1;
else return i2;
}
inline int sgn(float f) {
if(f>0.0) return 1;
else return -1;
}
/*############################################
############################################
########### Species class ###########
############################################
############################################*/
class Species {
public:
int s_nbind, /* nb of individuals per species */
s_dormDuration, /* seed dormancy duration -- not used in v.2.2 */
s_nbext; /* total number of incoming seeds in the simulated plot at each timestep (seed rain) -- v.2.2 */
char s_name[256]; /* species name */
float s_LCP, /* light compensation point (in micromol photon/m^2/s) */
s_Rdark, /* dark respiration rate (at PPFD = 0) in micromol C/m^2/s) */
s_ds, /* average dispersal distance */
// de1, /* (crown depth) - height slope deprecated v.2.1 */
s_dmax, /* maximal dbh (given in m) */
s_hmax, /* maximal height (given in m) */
s_dbh0, /* Initial dbh at recruitement, computed for each species with the species-specific allometric relationship at h=H0=1m -- in v230 */
s_Vcmax, /* maximal rate of carboxylation, on an area basis (in micromolC/m^2/s) */
s_Vcmaxm, /* maximal rate of carboxylation, on a mass basis (in micromolC/g-1/s) */
s_Jmax, /* maximal rate of electron transport, on an area basis (in micromol/m^2/s) */
s_Jmaxm, /* maximal rate of electron transport, on a mass basis (in micromol/g-1/s) */
s_fci, /* fraction of CO2 partial pressure in intercellular spaces divided by ambiant CO2 partial pressure (both in microbar, or ppm = micromol/mol) */
s_Gamma, /* compensation point for the carboxylation rate, here NORMALIZED by atm CO2 concentration (Cair) */
s_Km, /* apparent kinetic constant for the rubiscco = Kc*(1+[O]/Ko), here normalized by atm CO2 concentration (Cair) */
//s_d13C, /* isotopic carbon discrimination NOW normalized at zero height -- deprecated v.2.2 */
s_LMA, /* leaf mass per area (in g/m^2) */
s_Nmass, /* leaf nitrogen concentration (in g/g) v.2.01 */
s_Pmass, /* leaf phosphorous concentration (in g/g) v.2.01 */
s_wsg, /* wood specific gravity (in g/cm^3) */
s_ah, /* parameter for allometric height-dbh equation */
s_seedmass, /* seed mass, in g (from Baraloto & Forget 2007 dataset, in classes) v.2.3: seeminlgy deprecated in v.2.2, but still necessary for SEEDTRADEOFF */
s_iseedmass, /* inverse of seed mass, v.2.3: seeminlgy deprecated in v.2.2, but still necessary for SEEDTRADEOFF */
//s_factord13Ca, /* deprecated v.2.2 -- factor used for a previous version of ci/ca ratio computation, from d13C value */
//s_factord13Cb, /* deprecated v.2.2 -- factor used for a previous version of ci/ca ratio computation, from d13C value */
/* Below: new in v.2.2 */
s_leaflifespan, /* average leaf lifespan, in month */
s_time_young, /* leaf resident time in the young leaf class */
s_time_mature, /* leaf resident time in the mature leaf class */
s_time_old, /* leaf resident time in the old leaf class */
s_output_field[24]; /* scalar output fields per species (<24) */
#ifdef DCELL
int *s_DCELL; /* number of seeds from the species in each dcell */
int *s_Seed; /* presence/absence of seeds at each site; if def SEEDTRADEOFF, the number of seeds */
#else
int *s_Seed; /* presence/absence of seeds; if def SEEDTRADEOFF, the number of seeds */
#endif
#ifdef MPI
unsigned char *s_Gc[4]; /* MPI: seeds on neighboring procs */
#endif
Species() {
s_nbind=0;
s_Seed=0;
#ifdef DCELL
s_DCELL=0;
#endif
}; /* constructor */
virtual ~Species() {
delete [] s_Seed;
#ifdef DCELL
delete [] s_DCELL;
#endif
}; /* destructor */
void Init(int,fstream&); /* init Species class */
#ifdef DCELL
void FillSeed(int,int,int); /* assigns the produced seeds to s_DCELL */
#else
void FillSeed(int,int); /* fills s_Seed field (and s_Gc (MPI)) */
#endif
void UpdateSeed(void); /* Updates s_Seed field */
#ifdef MPI
void AddSeed(void); /* MPI: adds fields s_Gc to field s_Seed */
#endif
inline float DeathRateNDD(float, float,int, float); /* _NDD, overloading with function in following line */
inline float DeathRate(float, float, int); /* actual death rate -- new argument int v.2.2 */
inline float GPPleaf(float, float, float); /* Computation of the light-limited leaf-level NPP per m^2 (in micromol/m^2/s) -- two new arguments float v.2.2 */
/* Farquhar von Caemmerer Berry model */
inline float dailyGPPleaf(float, float, float, float, float); /* computation of the daily average assimilation rate, taking into account the daily variation in light, VPD and temperature two new arguments float v.2.2, _DAILYLIGHT */
};
/*############################
### Initialize Species ###
### Species::Init ###
############################*/
void Species::Init(int nesp,fstream& is) {
int site;
float regionalfreq; // "regional" relative abundance of the species -- new name v.2.2
float SLA; // specific leaf area = 1/LMA
/*** Read parameters ***/
//new input file -- in v230
is >> s_name >> s_LMA >> s_Nmass >> s_Pmass >> s_wsg >> s_dmax >> s_hmax >> s_ah >> s_seedmass >> regionalfreq;
// instead of seedmass we are given seedvolume
// from this we assume a conversion factor of 1 to wet mass (~density of water, makes seeds float)
// to convert to drymass we use a conversion factor of 0.4 (~40% of the seed are water)
s_seedmass *= 0.4;
s_iseedmass=1.0/s_seedmass;
s_ds=40.0;
s_dbh0=s_ah*H0/(s_hmax-H0);
#ifdef DCELL
/* NEW in 2.3.1: input of seeds per timestep and per dcell is assumed proportional to seed size (large seeds are less numerous) this is compensated for by a lower recruitment probability for small seeds compared to large ones. Thus, in essence, we still have the seed number regeneration tradeoff but we allow more stochasticity in this process. Also, at least one seed arrives in the dcell from each species at each timestep (this is the +1 term) */
#endif
// uniform composition of the seed rain -- in v230
regionalfreq=1.0/float(numesp);
if(_SEEDTRADEOFF){
s_nbext = (int(regionalfreq*Cseedrain*s_iseedmass)+1);
}
else {
s_nbext = int(regionalfreq*Cseedrain*(sites*LH*LH/10000));
}
SLA=10000.0/s_LMA; // computation of specific leaf area in cm^2/g for use in Domingues et al 2010 model of photosynthetic capacities
//s_leaflifespan=1.5+pow(10,(7.18+3.03*log10(s_LMA*0.0001))); //this is the expression from Reich et al 1991 Oecologia (San Carlos Rio Negro).
s_leaflifespan=pow(10,(2.040816*(2.579713-log10(SLA)))); //this is the expression from Reich et al. 1997 PNAS (provides probably more realistic estimates for species with high LMA).
//s_leaflifespan=0.5+pow(10,(-2.509+1.71*log10(s_LMA))); //this is the expression from Wright et al 2004 Nature (leaf economics spectrum).
s_time_young=1;
s_time_mature=s_leaflifespan/3.0;
s_time_old=s_leaflifespan-s_time_mature-s_time_young;
/*** Normalization of the parameters ***/
/* vertical (NV) and horizontal (NH) scales */
s_ah *= NV*LH;
s_ds *= NH;
s_hmax *= NV;
s_dmax *= NH;
s_dbh0 *= NH;
s_nbind=0;
s_fci = 0.0;
s_Vcmaxm=pow(10.0, minf((-1.56+0.43*log10(s_Nmass*1000.0)+0.37*log10(SLA)), (-0.80+0.45*log10(s_Pmass*1000.0)+0.25*log10(SLA))));
// this is equation 2 in Domingues et al 2010 PCE (coefficients from fig7) which made better fits than equation 1 (without LMA)
s_Jmaxm=pow(10.0, minf((-1.50+0.41*log10(s_Nmass*1000.0)+0.45*log10(SLA)), (-0.74+0.44*log10(s_Pmass*1000.0)+0.32*log10(SLA))));
// added as a Species member variable 14-04-2015; this is equ 2 in Domingues et al 2010 PCE (coefficients from fig7)
s_Vcmax=s_Vcmaxm*s_LMA;
s_Jmax=s_Jmaxm*s_LMA;
s_Rdark=s_LMA*(8.5341-130.6*s_Nmass-567.0*s_Pmass-0.0137*s_LMA+11.1*s_Vcmaxm+187600.0*s_Nmass*s_Pmass)*0.001;
//s_Rdark corresponds to leaf maintenance respiration. From Table 6 in Atkin et al 2015 New phytologist v.2.0 */
//s_Rdark=(82.36*(s_LMA*1e-3)-0.1561)*(s_LMA*1e-3); /* from Domingues et al 2007 */
//s_Rdark=0.01*s_Vcmax; /* parameterization of Rdark commonly used in vegetation models */
//s_Rdark=0.02*s_Vcmax-0.01; /* parameterization of von Caemmerer 2000 Table 2.3 page 45 */
s_Gamma = 38.0*iCair;
// s_Gamma at 25°C computed according to von Caemmerer 2000 formula: gamma=Kc*O*0.25/(2*Ko), with Kc=260 microbar, Ko=179mbar and O=210 mbar (the last value is from Farquhar et al 1980, the first two one are from von Caemmerer 2000 table 2.3 page 45). gamma is set to 36.9 on Atkin et al 2015. Could be a global variable. v.2.0
s_LCP = s_Rdark/phi; /* Computation of the light compensation point from dark respiration and the quantum yield phi. By definition, Rdark is in micromolC/m^2/s and it is used in the Species::NPP() routine */
#ifdef DCELL
if (NULL==(s_DCELL = new int[nbdcells])) cerr<<"!!! Mem_Alloc s_DCELLn";
for(int dcell=0;dcell<nbdcells;dcell++) s_DCELL[dcell]=0;
/*** field initialization ***/
if (NULL==(s_Seed = new int[sites])) cerr<<"!!! Mem_Alloc\n";
for(site=0;site<sites;site++) s_Seed[site]=0;
#else
/*** field initialization ***/
if (NULL==(s_Seed = new int[sites])) cerr<<"!!! Mem_Alloc\n";
for(site=0;site<sites;site++) s_Seed[site]=0;
#endif
#ifdef MPI
for(int i=0;i<4;i++) {
if (NULL==(s_Gc[i] = new unsigned char[sites])) cerr<<"!!! Mem_Alloc\n";
for(site=0;site<sites;site++) s_Gc[i][site]=0;
}
#endif
}
/*############################
### Species Seeds ###
### Species::FillSeed ###
### Species::UpdateSeed ###
### Species::AddSeed ###
#############################*/
/*### Species::FillSeed ###*/
/* creates one seed at point (col,row) */
#ifdef DCELL
/* in the new approach with a mean field seed flux (DCELL), the function FillSeed has a new
role: it fills the vector s_DCELL that stores the number of produced seeds per timestep and per dcell */
void Species::FillSeed(int dcol, int drow, int nbs) {
s_DCELL[dcol+linear_nb_dcells*drow]+=nbs;
}
#else
void Species::FillSeed(int col, int row) {
int site;
if(col < cols) {
if((row >=0) && (row < rows)) {
site=col+cols*row;
if(_SEEDTRADEOFF){
s_Seed[site]++; /* ifdef SEEDTRADEOFF, s_Seed[site] is the number of seeds of this species at that site */
}
else{
if(s_Seed[site]!=1) s_Seed[site]=1; /* If s_Seed[site] = 0, site is not occupied, if s_Seed[site] > 1, s_Seed[site] is the age of the youngest seed */
}
}
#ifdef MPI /* on each processor a stripe of forest is simulated.
Nearest neighboring stripes are shared. Rque, this version is not valid ifdef SEEDTRADEOFF */
else if((row+rows >=0) && (row < 0)) {
site=col+cols*(row+rows);
if(s_Gc[0][site]!=1) s_Gc[0][site]=1;
}
else if((row >=rows) && (row < 2*rows)) {
site=col+cols*(row-rows);
if(s_Gc[1][site]!=1) s_Gc[1][site]=1;
}
#endif
}
}
#endif
/*### Species::UpdateSeed ###*/
/* updates s_Seed field */
/* new in v.2.3: not called within loop over sites, instead includes loop --> less function calling, BUT: no check of site occupation anymore, cf. below */
#ifdef DCELL
/* in the new approach with a mean field seed flux (DCELL), the function UpdateSeed
has a new role: it uses the vector s_DCELL to fill the s_Seed local seed bank */
void Species::UpdateSeed() {
int site;
for(site=0;site<sites;site++) s_Seed[site]=0;
for(int dcell=0;dcell<nbdcells;dcell++){ // loop over dcells
int localseeds=min(s_DCELL[dcell],sites_per_dcell);
// store number of seeds in this dcell
// localseeds is capped by the max number of available sites in the dcell
s_DCELL[dcell]=0;
gsl_ran_multinomial(gslrand,sites_per_dcell,localseeds,prior_DCELL,post_DCELL);
//cerr << "Localseeds in dcell\t" << dcell << " : " << localseeds << endl;
/*float sumprior=0.0,sumpost=0;
for(int i=0;i<sites_per_dcell;i++){
sumprior+=prior_DCELL[i];sumpost+=post_DCELL[i];
}*/
//cerr <<"localseeds\t"<< localseeds << "\tsumprior\t"<< sumprior << "\tsumpost\t"<< sumpost << "\n";
// sample equiprobably all the sites in the dcell
for(int i=0;i<sites_per_dcell;i++){ // update the s_Seed site
site=MAP_DCELL[dcell][i];
s_Seed[site] = post_DCELL[i];
//cerr << "site\t" << site << "\tdcell\t" << dcell << "\tlocal_site\t" << i << "\tpost_DCELL[i]\t" << post_DCELL[i] << "\ts_Seed[site]\t" << s_Seed[site] << endl;
}
}
/*int summ=0;
for(site=0;site<sites;site++) summ=summ+s_Seed[site];
cerr << "Localseeds of species \t" << s_name << "\t: " << summ << endl; */
}
#else
void Species::UpdateSeed() {
/* should probably be modified, since as implemented now seeds are erased every timestep (i.e. month in default mode)--> to be discussed */
if(_SEEDTRADEOFF){
for(int site=0;site<sites;site++){
# ifdef MPI
s_Gc[0][site]=s_Gc[1][site]=s_Gc[2][site]=s_Gc[3][site]=0;
#endif
s_Seed[site]=0;
}
}
else{
/* new in v.2.3: version 2.2 checked whether site was occupied by tree: T[site].t_age>0) s_Seed[site]=0; */
/* v.2.3 does not do this within UpdateSeed() anymore. Instead, it sets all occupied sites to zero directly within UpdateTree() */
for(int site=0;site<sites;site++){
# ifdef MPI
s_Gc[0][site]=s_Gc[1][site]=s_Gc[2][site]=s_Gc[3][site]=0;
#endif
/* seed bank ages or disappears */
if(s_Seed[site]==s_dormDuration) s_Seed[site]=0;
else if(s_Seed[site]!=0) s_Seed[site]++; // v.2.3: bug fix: before, procedure was not restricted to existing seeds, therefore creation of seeds
}
}
}
#endif
#ifdef MPI
/* deprecated in v.2 -- needs a new concept for spatial parallelization -- hopefully soon */
/*########################################
### Calculation of shared fields s_Gc ###
########################################*/
void Species::AddSeed() {
/* Stripes shared by several processors are redefined */
for(int site=0;site<sites;site++) {
if(p_rank){
if(!s_Seed[site]) s_Seed[site] = s_Gc[2][site];
if(s_Seed[site]>1)
if(s_Gc[2][site]) s_Seed[site] = min(s_Seed[site],s_Gc[2][site]);
}
if(p_rank<size-1){
if(!s_Seed[site]) s_Seed[site] = s_Gc[3][site];
if(s_Seed[site]>1)
if(s_Gc[3][site]) s_Seed[site] = min(s_Seed[site],s_Gc[3][site]);
}
}
}
#endif
/*############################
### Species::DeathRate ###
#############################*/
/* Here we assume a light-dependent version of the mortality.
basal is the minimal species death rate, depending on the species wood density.
When PPFD is smaller than the light compensation point, mortality risk is increased.
When NDD is defined, this death rate is increased by density-dependence effect that impact survival of trees with a dbh<10cm . */
/* v.2.2 Simplify function Species::DeathRate -- JChave */
/* Changed v.2.2, _NDD */
/* v;2.3.0 function has been renamed to avoid possible confusion downstream */
inline float Species::DeathRateNDD(float PPFD, float dbh, int nppneg, float ndd) {
float dr=0;
float basal=m*(1-s_wsg);
float dd=deltaD*ndd*(1-2*dbh/s_dmax);
dr=basal;
if (nppneg > s_leaflifespan) {
dr+=1.0/timestep;
}
if (dd > 0) {
dr+=dd;
}
return dr*timestep;
}
inline float Species::DeathRate(float PPFD, float dbh, int nppneg) {
float dr=0;
float basal=m-m1*s_wsg;
dr=basal;
if (nppneg > s_leaflifespan) dr+=1.0/timestep;
if (iter == int(nbiter-1))
output[26]<< s_wsg << "\t" << basal << "\t" << dbh << "\t" << dr << "\n";
return dr*timestep;
}
/*#############################################
### Farquhar von Caemmerer Berry model ###
### Species:: NPP ###
#############################################*/
/* This function returns the leaf-level carbon assimilation rate in micromoles C/m^2/s according to Farquhar-von Caemmerer-Berry model */
/* The function Species::dailyGPPleaf returns the primary productivity per unit leaf area, i.e. in micromoles C/m^2/s.
It is converted into gC per m^2 of leaf per timestep by "*189.3*timestep" accounting only for the light hours (12 hours instead of 24): 189.3=12*3600*365.25*12/1000000
BEWARE: 12 is the molar mass of C, and also the number of light hours in a day
BEWARE: timestep is given as fraction of a year, so what is computed is actually the full assimilation per year which, in turn, is multiplied by the fraction per year that is under consideration
BEWARE: slight inconsistency through use of 365.25 when daily timestep is likely to be given as 365, but not incorrect
Commented version below was in use prior to version 2.3.0 -- use of lookup tables for acceleration of T dependence. cf. Bernacchi et al 2003 PCE; von Caemmerer 2000
derivation of s_fci (ci/ca) according to Medlyn et al 2011, see also Prentice et al 2014 Ecology Letters and Lin et al 2015 Nature Climate Change --- initial version: s_fci = minf(-0.04*s_d13C-0.3*(log(PPFD)-s_factord13Cb)*s_factord13Ca-0.57, 1.0);
from d13C (see cernusak et al 2013) without explicit model of stomatal conductance; min added in order to prevent ci:ca bigger than 1 (even though Ehleringer et al 1986 reported some values above 1 (Fig3) */
inline float Species::GPPleaf(float PPFD, float VPD, float T) {
/* v.2.3.0: theta defined as a global variable */
//theta=0.7; // this is the fixed value of theta used by von Caemmerer 2000
//float theta=0.76+0.018*T-0.00037*T*T; // theta, but temperature dependent cf. Bernacchi et al 2003 PCE
/* Parameters for Farquhar model, with temperature dependencies */
int convT= int(iTaccuracy*T); // temperature data at a resolution of Taccuracy=0.1°C -- stored in lookup tables ranging from 0°C to 50°C ---
float KmT =LookUp_KmT[convT];
float GammaT =LookUp_GammaT[convT];
tempRday +=s_Rdark*LookUp_tempRday[convT];
float VcmaxT =s_Vcmax*LookUp_VcmaxT[convT];
float JmaxT =s_Jmax*LookUp_JmaxT[convT];
s_fci=g1/(g1+sqrt(VPD));
/* FvCB model */
float I=alpha*PPFD;
float J = (I+JmaxT-sqrt((JmaxT+I)*(JmaxT+I)-4.0*theta*JmaxT*I))*0.5/theta;
float A = minf(VcmaxT/(s_fci+KmT),0.25*J/(s_fci+2.0*GammaT))*(s_fci-GammaT);
return A;
}
/* dailyGPPleaf returns the assimilation rate (computed from Species::GPPleaf) averaged across the daily fluctuations in climatic conditions (light, VPD and T), in micromoles C/m^2/s */
/* used only by _DAILYLIGHT */
inline float Species::dailyGPPleaf(float PPFD, float VPD, float T, float dens, float CD) {
float ppfde,dailyA=0.0;
for(int i=0; i<24; i++) {
ppfde=PPFD*daily_light[i];
if(ppfde > 0.1)
// new v.2.3.0: compute GPP only if enough light is available threshold is arbitrary, but set to be low: in full sunlight ppfd is aroung 700 W/m2, and even at dawn, it is ca 3% of the max value, or 20 W/m2. The minimum threshold is set to 0.1 W/m2
// Future update: compute slightly more efficiently, using 3-hourly values? This will have to be aligned with climate forcing layers (e.g. NCAR)
dailyA+=GPPleaf(ppfde, VPD*daily_vpd[i], T*daily_T[i]);
//the 6 lines in comment below corresponds to a finer version in which the multiplier is computed and used every 48 half hour, ie. with the corresponding environment instead of assuming a constant multiplier correponding the one at maximum incoming irradiance
//float hhA=0;
//hhA=GPPleaf(PPFD*daily_light[i], VPD*daily_vpd[i], T*daily_T[i]);
//float alpha=phi*PPFD*daily_light[i]/hhA;
//float D=klight*dens*CD;
//hhA*=alpha/(D*(alpha-1))*log(alpha/(1+(alpha-1)*exp(-D)));
//dailyA+=hhA;
}
//daily_light is the averaged (across one year, meteo station Nouragues DZ) and normalized (from 0 to 1) daily fluctuation of light, with half-hour time step, during the day time (from 7am to 7pm, ie 12 hours in total), same for daily_vpd and daily_T. Taking into account these daily variation is necessary considering the non-linearity of FvCB model
if(_FASTGPP){
float alpha=phi*PPFD/GPPleaf(PPFD, VPD, T); //alpha is a non-dimensional figure used to compute the multiplier below
float D=klight*dens*CD; //D is a non-dimensional figure used to compute the multiplier below
float m=alpha/(D*(alpha-1))*log(alpha/(1+(alpha-1)*exp(-D)));
if (m>=1.0 || CD > 7.0) {
cout << "m pb FASTGPP !!!" << endl;
}
dailyA*=alpha/(D*(alpha-1))*log(alpha/(1+(alpha-1)*exp(-D))); // the FvCB assimilation rate computed at the top of the tree crown is multiplied by a multiplier<1, to account for the lower rate at lower light level within the crown depth. This multiplier is computed assuming that change in photosynthetic assimilation rate within a tree crown is mainly due to light decrease due to self-shading following a Michealis-menten relationship (ie. we assume that 1/ the change is not due to changes in VPD or temperature, which are supposed homogeneous at the intra-crown scale, and 2/ that other tree contributions to light decrease is neglected).
}
dailyA*=0.0417; // 0.0417=1/24 (24=12*2 = number of half hours in the 12 hours of daily light)
tempRday*=0.0417;
return dailyA;
}
/*############################################
############################################
############ Tree class ############
############################################
############################################*/
class Tree {
private:
float t_C; /* flexural force intensity, _TREEFALL, float? */
public:
int t_site, /* location */
t_NPPneg; /* diagnostic variable: number of consecutive timesteps with NPP<0 -- V.2.2 */
float t_dbh_thresh, /* dbh threshold */
t_hmax, /* hmax, but not real maximum */
t_angle, /* orientation of applied force, _TREEFALL */
t_dbhmature, /* reproductive size threshold IM janv2017 -- v230 */
t_dbh, /* diameter at breast height (in m, but used in number of horizontal cells throughout all the code) */
t_Tree_Height, /* total tree height (in m, but used in number of vertical cells throughout all the code) */
t_Crown_Depth, /* crown depth (in m, but used in number of vertical cells throughout all the code) */
t_Crown_Radius, /* crown radius (in m, but used in number of horizontal cells throughout all the code)*/
t_Ct, /* flexural force threshold, _BASICTREEFALL */
t_GPP, /* tree gross primary productivity */
t_NPP, /* tree net primary productivity (in gC/timestep) */
t_Rday, /* leaf respiration during day */
t_Rnight, /* leaf respiration during night */
t_Rstem, /* stem respiration */
t_PPFD, /* light intensity received by the tree (computed by Tree::Flux, depending of the LAI at the tree height) */
t_VPD, /* VPD at tree height -- v.2.2 */
t_T, /* Temperature at tree height -- v.2.2 */
t_ddbh, /* increment of dbh per timestep */
t_age, /* tree age */
t_youngLA, /* total young leaf area, in m2 -- v.2.2 */
t_matureLA, /* total mature leaf area, in m2 -- v.2.2 */
t_oldLA, /* total old leaf area, in m2 -- v.2.2 */
t_leafarea, /* total crown leaf area in m2 -- v.2.2 */
t_dens, /* tree crown average leaf density in m2/m2 -- v.2.2 */
t_litter; /* tree litterfall at each timestep, in g (of dry mass) -- v.2.2 */
float *t_NDDfield; /* _NDD */
Species *t_s;
unsigned short
t_from_Data, /* indicator of whether tree is born through initialisation or through simulation routine */
t_sp_lab, /* species label */
t_hurt; /* treefall index */
Tree(){ /* constructor */
t_from_Data = 0;
t_sp_lab = 0;
t_age = 0;
t_hurt = 0;
t_NPP=t_GPP=t_Rday=t_Rnight=t_Rstem=t_PPFD=t_VPD=t_T=0.0; /* new v.2.2 */
if(_TREEFALL){
t_C = 0;
t_angle = 0.0;
}
if(_BASICTREEFALL) t_Ct = 0.0;
t_dbh = t_Tree_Height = t_Crown_Radius = 0.0;
};
virtual ~Tree() {
delete [] t_NDDfield; /* _NDD */
}; /* destructor */
void Birth(Species*,int,int); /* tree birth */
void BirthFromData(Species *S, int nume, int site0, float dbh_measured); /* tree initialisation from field data */
void Death(); /* tree death */
void Growth(); /* tree growth */
void Fluxh(int h); /* compute mean light flux received by the tree crown layer at height h new version (PPFD symmetrical with T and VPD) -- v230 */
void UpdateLeafDynamics(); /* computes within-canopy leaf dynamics (IM since v 2.1, as a standalone function in v.2.3.0) */
void UpdateTreeBiometry(); /* compute biometric relations, including allometry -- contains a large part of empirical functions */
int Couple(); /* force exerted by other trees, _TREEFALL */
void DisperseSeed(); /* update Seed field */
void FallTree(); /* tree falling routine, _TREEFALL */
void Update(); /* tree evolution at each timestep */
void Average(); /* local computation of the averages */
void CalcLAI();
//void TrunkLAI(); /* computation of trunk LAI -- deprecated v.2.2 */
void histdbh(); /* computation of dbh histograms */
void OutputTreeStandard(); /* creates standard output for trees, writes directly to cout stream */
void OutputTreeStandard(fstream& output); /* overloading of function, creates standard output for trees */
};
/*##############################################
#### Tree birth ####
#### called by BirthInit and UpdateTree ####
##############################################*/
void Tree::Birth(Species *S, int nume, int site0) {
t_site = site0;
t_sp_lab = nume; /* t_sp_lab is the species label of a site. Can be defined even if the site is empty (cf. persistence function defined in Chave, Am Nat. 2001) */
t_NPPneg=0.0;
t_s = S+t_sp_lab;
t_age = 1;
t_hurt = 0;
t_dbh=(t_s->s_dbh0);
t_ddbh=0.0;
t_dbh_thresh = ((t_s->s_dmax)-t_dbh)*flor(1.0+log(genrand2())*0.01)+t_dbh;
t_hmax = (t_s->s_hmax);
t_Tree_Height = H0;
t_Crown_Radius = ra0;
t_Crown_Depth = de0;
t_dens=dens;
t_youngLA=t_dens*PI*t_Crown_Radius*LH*t_Crown_Radius*LH*t_Crown_Depth*LV;
/* initially, all stems have only young leaves -- LA stands for leaf area */
t_matureLA=0; /* this is the amount of leaf area at maturity */
t_oldLA=0; /* leaf area of senescing leaves */
t_leafarea=t_youngLA; /* should be sum of LA young+mature+old, but the equation is correct initially */
tempRday=0.0;
float hrealmax=3*t_hmax * t_dbh_thresh/(3*t_dbh_thresh + 2*t_s->s_ah);
t_dbhmature=t_s->s_dmax*0.5; // this correponds to the mean thresholds of tree size to maturity, according to Visser et al. 2016 Functional Ecology (suited to both understory short-statured species, and top canopy large-statured species). NOTE that if we decide to keep it as a fixed species-specific value, this could be defined as a Species calss variable, and computed once in Species::Init. -- v230
//float u=genrand2();
//t_dbhmature=maxf(0, -(t_s->s_dmax)*0.25*log((1-u)/u)+t_s->s_dmax*0.5); // IM test 02-2017, try to introduce intra-species inter-individual variability in dbhmature, following a sigmoidal repartition function, as in Visser et al. 2016 and Wright et al. 2005
if(_BASICTREEFALL) t_Ct = hrealmax*flor(1.0-vC*sqrt(-log(genrand2())));
(t_s->s_nbind)++;
nblivetrees++;
/* setting diagnostic variables */
}
/*##############################################
#### Tree Initialization from Data ####
##############################################*/
void Tree::BirthFromData(Species *S, int nume, int site0, float dbh_measured) {
// entirely modelled following Tree::Birth
// main differences: dbh is given, related parameters are not set to fixed initial values, but derived through allometries
// for comments regarding allometries and t_leafarea cf. Tree::Growth
// for comments regarding everything else cf. Tree::Birth
t_site = site0;
t_sp_lab = nume;
t_NPPneg=0;
t_s = S+t_sp_lab;
t_age = 1; //value not correct, but generally not problematic, used mainly as diagnostic variable and as indicator of whether tree is alive or not (death itself is independent of age), BUT: use as diagnostic variable cannot be ensured anymore and be careful if conditioning on t_age (e.g. for maturation)
t_from_Data = 1; //indicates that tree stems from data (and therefore t_age could not be used, etc.)
t_hurt = 0;
if((t_s->s_dmax)*1.5 > dbh_measured) t_dbh = dbh_measured; // force dbh to be within limits of TROLL specifications
else {
t_dbh = (t_s->s_dmax);
cout << "Warning: DBH_measured > 1.5*DBH_max for species. DBH set to DBH_max for species \n";
}
t_ddbh=0.0;
t_dbh_thresh = (t_s->s_dmax);
t_hmax = (t_s->s_hmax);
t_Tree_Height = t_hmax * t_dbh/(t_dbh + (t_s->s_ah));
t_Crown_Radius = 0.80+10.47*t_dbh-3.33*t_dbh*t_dbh;;
if (t_Tree_Height<5.0) t_Crown_Depth = 0.133+0.168*t_Tree_Height;
else t_Crown_Depth = -0.48+0.26*t_Tree_Height;
t_dens=dens;
t_leafarea=t_dens*PI*t_Crown_Radius*LH*t_Crown_Radius*LH*t_Crown_Depth;
t_youngLA=0.25*t_leafarea;
t_matureLA=0.5*t_leafarea;
t_oldLA=0.25*t_leafarea;
Fluxh(int(t_Tree_Height)+1);
tempRday=0.0;
/* v.2.3.0 in version 2.3 and prior, fluxes were also initialized, resulting in a longer code, with multiple repetitions of the same empirical functions. It is better *NOT* to call empirical functions more than once. */
float hrealmax = 3*t_hmax * t_dbh_thresh/(3*t_dbh_thresh + 2*t_s->s_ah);