diff --git a/SW_Control.c b/SW_Control.c index a3a77b344..978a19e8e 100644 --- a/SW_Control.c +++ b/SW_Control.c @@ -160,7 +160,7 @@ void SW_CTL_init_run(void) { SW_PET_init_run(); SW_SKY_init_run(); SW_SIT_init_run(); - // SW_VES_init_run() not needed + SW_VES_init_run(); // must run after `SW_SIT_init_run()` SW_VPD_init_run(); SW_FLW_init_run(); SW_ST_init_run(); diff --git a/SW_VegEstab.c b/SW_VegEstab.c index ccbf07805..d9cac9df1 100644 --- a/SW_VegEstab.c +++ b/SW_VegEstab.c @@ -45,6 +45,7 @@ #include "SW_Model.h" // externs SW_Model #include "SW_SoilWater.h" // externs SW_Soilwat #include "SW_Weather.h" // externs SW_Weather +#include "SW_VegProd.h" // externs `key2veg[]` #include "SW_VegEstab.h" @@ -130,7 +131,7 @@ void SW_VES_deconstruct(void) // De-allocate days and parameters if (SW_VegEstab.count > 0) { - if (!isnull(SW_VegEstab.p_oagg[pd]->days)) { + if (pd > eSW_Day && !isnull(SW_VegEstab.p_oagg[pd]->days)) { Mem_Free(SW_VegEstab.p_oagg[eSW_Year]->days); } @@ -190,27 +191,44 @@ void SW_VES_read(void) { CloseFile(&f); SW_VegEstab_construct(); - - if (EchoInits) - _echo_VegEstab(); } /** -@brief Construct SW_VegEstab variable +@brief Construct SW_VegEstab output variables */ void SW_VegEstab_construct(void) { + if (SW_VegEstab.count > 0) { + SW_VegEstab.p_oagg[eSW_Year]->days = (TimeInt *) Mem_Calloc( + SW_VegEstab.count, sizeof(TimeInt), "SW_VegEstab_construct()"); + + SW_VegEstab.p_accu[eSW_Year]->days = (TimeInt *) Mem_Calloc( + SW_VegEstab.count, sizeof(TimeInt), "SW_VegEstab_construct()"); + } +} + + +/** + @brief Initialization and checks of species establishment parameters + + This works correctly only after + * species establishment parameters are read from file by `SW_VES_read()` + * soil layers are initialized by `SW_SIT_init_run()` +*/ +void SW_VES_init_run(void) { IntU i; - for (i = 0; i < SW_VegEstab.count; i++) + for (i = 0; i < SW_VegEstab.count; i++) { _spp_init(i); + } - if (SW_VegEstab.count > 0) { - SW_VegEstab.p_accu[eSW_Year]->days = (TimeInt *) Mem_Calloc( - SW_VegEstab.count, sizeof(TimeInt), "SW_VegEstab_construct()"); + if (EchoInits) { + _echo_VegEstab(); } } + + /** @brief Check that each count coincides with a day of the year. */ @@ -327,7 +345,7 @@ static void _zero_state(unsigned int sppnum) { static void _read_spp(const char *infile) { /* =================================================== */ SW_VEGESTAB_INFO *v; - const int nitems = 15; + const int nitems = 16; FILE *f; int lineno = 0; char name[80]; /* only allow 4 char sppnames */ @@ -347,45 +365,48 @@ static void _read_spp(const char *infile) { strcpy(name, inbuf); break; case 1: - v->estab_lyrs = atoi(inbuf); + v->vegType = atoi(inbuf); break; case 2: - v->bars[SW_GERM_BARS] = fabs(atof(inbuf)); + v->estab_lyrs = atoi(inbuf); break; case 3: - v->bars[SW_ESTAB_BARS] = fabs(atof(inbuf)); + v->bars[SW_GERM_BARS] = fabs(atof(inbuf)); break; case 4: - v->min_pregerm_days = atoi(inbuf); + v->bars[SW_ESTAB_BARS] = fabs(atof(inbuf)); break; case 5: - v->max_pregerm_days = atoi(inbuf); + v->min_pregerm_days = atoi(inbuf); break; case 6: - v->min_wetdays_for_germ = atoi(inbuf); + v->max_pregerm_days = atoi(inbuf); break; case 7: - v->max_drydays_postgerm = atoi(inbuf); + v->min_wetdays_for_germ = atoi(inbuf); break; case 8: - v->min_wetdays_for_estab = atoi(inbuf); + v->max_drydays_postgerm = atoi(inbuf); break; case 9: - v->min_days_germ2estab = atoi(inbuf); + v->min_wetdays_for_estab = atoi(inbuf); break; case 10: - v->max_days_germ2estab = atoi(inbuf); + v->min_days_germ2estab = atoi(inbuf); break; case 11: - v->min_temp_germ = atof(inbuf); + v->max_days_germ2estab = atoi(inbuf); break; case 12: - v->max_temp_germ = atof(inbuf); + v->min_temp_germ = atof(inbuf); break; case 13: - v->min_temp_estab = atof(inbuf); + v->max_temp_germ = atof(inbuf); break; case 14: + v->min_temp_estab = atof(inbuf); + break; + case 15: v->max_temp_estab = atof(inbuf); break; } @@ -443,33 +464,78 @@ static void _sanity_check(unsigned int sppnum) { /* =================================================== */ SW_LAYER_INFO **lyr = SW_Site.lyr; SW_VEGESTAB_INFO *v = SW_VegEstab.parms[sppnum]; - LyrIndex min_transp_lyrs; - int k; - min_transp_lyrs = SW_Site.n_transp_lyrs[SW_TREES]; - ForEachVegType(k) { - min_transp_lyrs = min(min_transp_lyrs, SW_Site.n_transp_lyrs[k]); + + if (v->vegType > NVEGTYPES) { + LogError( + logfp, + LOGFATAL, + "%s (%s) : Specified vegetation type (%s [%d]) is not implemented.", + MyFileName, + v->sppname, + key2veg[v->vegType], + v->vegType + ); } - if (v->estab_lyrs > min_transp_lyrs) { - LogError(logfp, LOGFATAL, "%s : Layers requested (estab_lyrs) > (# transpiration layers=%d).", MyFileName, min_transp_lyrs); + if (v->estab_lyrs > SW_Site.n_transp_lyrs[v->vegType]) { + LogError( + logfp, + LOGFATAL, + "%s (%s) : Layers requested (estab_lyrs = %d) > " + "(# transpiration layers = %d).", + MyFileName, + v->sppname, + v->estab_lyrs, + SW_Site.n_transp_lyrs[v->vegType] + ); } if (v->min_pregerm_days > v->max_pregerm_days) { - LogError(logfp, LOGFATAL, "%s : First day of germination > last day of germination.", MyFileName); + LogError( + logfp, + LOGFATAL, + "%s (%s) : First day of germination > last day of germination.", + MyFileName, + v->sppname + ); } if (v->min_wetdays_for_estab > v->max_days_germ2estab) { - LogError(logfp, LOGFATAL, "%s : Minimum wetdays after germination (%d) > maximum days allowed for establishment (%d).", MyFileName, v->min_wetdays_for_estab, - v->max_days_germ2estab); + LogError( + logfp, + LOGFATAL, + "%s (%s) : Minimum wetdays after germination (%d) > " + "maximum days allowed for establishment (%d).", + MyFileName, + v->sppname, + v->min_wetdays_for_estab, + v->max_days_germ2estab + ); } if (v->min_swc_germ < lyr[0]->swcBulk_wiltpt) { - LogError(logfp, LOGFATAL, "%s : Minimum swc for germination (%.4f) < wiltpoint (%.4f)", MyFileName, v->min_swc_germ, lyr[0]->swcBulk_wiltpt); + LogError( + logfp, + LOGFATAL, + "%s (%s) : Minimum swc for germination (%.4f) < wiltpoint (%.4f)", + MyFileName, + v->sppname, + v->min_swc_germ, + lyr[0]->swcBulk_wiltpt + ); } if (v->min_swc_estab < lyr[0]->swcBulk_wiltpt) { - LogError(logfp, LOGFATAL, "%s : Minimum swc for establishment (%.4f) < wiltpoint (%.4f)", MyFileName, v->min_swc_estab, lyr[0]->swcBulk_wiltpt); + LogError( + logfp, + LOGFATAL, + "%s (%s) : Minimum swc for establishment (%.4f) < wiltpoint (%.4f)", + MyFileName, + v->sppname, + v->min_swc_estab, + lyr[0]->swcBulk_wiltpt + ); } } @@ -512,7 +578,8 @@ void _echo_VegEstab(void) { strcpy(outstr, errstr); for (i = 0; i < SW_VegEstab.count; i++) { - sprintf(errstr, "Species: %s\n----------------\n" + sprintf( + errstr, "Species: %s (vegetation type %s [%d])\n----------------\n" "Germination parameters:\n" "\tMinimum SWP (bars) : -%.4f\n" "\tMinimum SWC (cm/cm) : %.4f\n" @@ -522,9 +589,18 @@ void _echo_VegEstab(void) { "\tFirst possible day : %d\n" "\tLast possible day : %d\n" "\tMinimum consecutive wet days (after first possible day): %d\n", - v[i]->sppname, v[i]->bars[SW_GERM_BARS], v[i]->min_swc_germ / lyr[0]->width, - v[i]->min_swc_germ, v[i]->min_temp_germ, v[i]->max_temp_germ, - v[i]->min_pregerm_days, v[i]->max_pregerm_days, v[i]->min_wetdays_for_germ); + v[i]->sppname, + key2veg[v[i]->vegType], + v[i]->vegType, + v[i]->bars[SW_GERM_BARS], + v[i]->min_swc_germ / lyr[0]->width, + v[i]->min_swc_germ, + v[i]->min_temp_germ, + v[i]->max_temp_germ, + v[i]->min_pregerm_days, + v[i]->max_pregerm_days, + v[i]->min_wetdays_for_germ + ); sprintf(errstr, "Establishment parameters:\n" "\tNumber of layers affecting successful establishment: %d\n" diff --git a/SW_VegEstab.h b/SW_VegEstab.h index bc6e69fcf..b80244aec 100644 --- a/SW_VegEstab.h +++ b/SW_VegEstab.h @@ -45,6 +45,7 @@ typedef struct { /* THESE VARIABLES DO NOT CHANGE DURING THE NORMAL MODEL RUN */ char sppFileName[MAX_FILENAMESIZE]; /* Store the file Name and Path, Mostly for Rsoilwat */ char sppname[MAX_SPECIESNAMELEN + 1]; /* one set of parms per species */ + unsigned int vegType; /**< Vegetation type of species (see "Indices to vegetation types") */ TimeInt min_pregerm_days, /* first possible day of germination */ max_pregerm_days, /* last possible day of germination */ min_wetdays_for_germ, /* number of consecutive days top layer must be */ @@ -75,7 +76,7 @@ typedef struct { typedef struct { TimeInt *days; /* only output the day of estab for each species in the input */ - /* this array is allocated via SW_VES_Init() */ + /* this array is allocated via `SW_VegEstab_construct()` */ /* each day in the array corresponds to the ordered species list */ } SW_VEGESTAB_OUTPUTS; @@ -102,7 +103,7 @@ extern SW_VEGESTAB SW_VegEstab; void SW_VES_read(void); void SW_VES_construct(void); void SW_VES_deconstruct(void); -void SW_VES_init(void); +void SW_VES_init_run(void); void SW_VegEstab_construct(void); void SW_VES_checkestab(void); void SW_VES_new_year(void); diff --git a/testing/Input/bouteloua.estab b/testing/Input/bouteloua.estab index 90d6eacdf..43662ab26 100644 --- a/testing/Input/bouteloua.estab +++ b/testing/Input/bouteloua.estab @@ -1,18 +1,19 @@ -bogr # 4-char name of species +bogr # 4-char name of species +3 # Vegetation type of species (0, trees; 1, shrubs; 2, forbs; 3 grasses) # soil layer parameters 2 # number of layers affecting establishment 10. # SWP (bars) requirement for germination (top layer) 15. # SWP (bars) requirement for establishment (average of top layers) # timing parameters in days 60 # first possible day of germination -180 # last possible day of germination +180 # last possible day of germination 2 # min number of consecutive "wet" days for germination to occur -40 # max number of consecutive "dry" days after germination allowing estab +40 # max number of consecutive "dry" days after germination allowing estab 5 # min number of consecutive "wet" days after germination before establishment -15 # min number of days between germination and establishment -75 # max number of days between germination and establishment +15 # min number of days between germination and establishment +75 # max number of days between germination and establishment # temperature parameters in C -5. # min temp threshold for germination -20. # max temp threshold for germination -0. # min temp threshold for establishment -20. # max temp threshold for establishment +5. # min temp threshold for germination +20. # max temp threshold for germination +0. # min temp threshold for establishment +20. # max temp threshold for establishment diff --git a/testing/Input/bromus.estab b/testing/Input/bromus.estab index 3ae2beebf..5fe061039 100644 --- a/testing/Input/bromus.estab +++ b/testing/Input/bromus.estab @@ -1,4 +1,5 @@ brte # 4-char name of species +3 # Vegetation type of species (0, trees; 1, shrubs; 2, forbs; 3 grasses) # soil layer parameters 3 # number of layers affecting establishment - 45 cm Harris and Hulbert 10. # SWP (bars) requirement for germination (top layer) - Harris @@ -7,7 +8,7 @@ brte # 4-char name of species 200 # first possible day of germination - Hulbert and Harris 365 # last possible day of germination - Hulbert 6 # min number of consecutive "wet" days for germination to occur - Hurlbert and Harris -45 # max number of consecutive "dry" days after germination allowing estab - Harris (longtime) +45 # max number of consecutive "dry" days after germination allowing estab - Harris (longtime) 6 # min number of consecutive "wet" days after germination before establishment - Harris 15 # min number of days between germination and establishment - Hulbert 90 # max number of days between germination and establishment - Harris and Hulbert @@ -15,4 +16,4 @@ brte # 4-char name of species 10. # min temp threshold for germination - Hulbert and Harris 30. # max temp threshold for germination - Hulbert and Harris 3. # min temp threshold for establishment - Harris -30. # max temp threshold for establishment - Harris and Hulbert +30. # max temp threshold for establishment - Harris and Hulbert