diff --git a/.gitignore b/.gitignore index 7d763156..65b06cbd 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,10 @@ nbproject/private/launcher.properties nbproject/private/private.xml nbproject/project.xml +# VScode project files +###################### +.vscode + # CLion project files cmake-build-debug/* .idea/* diff --git a/ST_defines.h b/ST_defines.h index 4f57050d..abf5e061 100644 --- a/ST_defines.h +++ b/ST_defines.h @@ -26,15 +26,15 @@ /*************************************************** * Basic definitions ***************************************************/ -#define MAX_SPECIES (Globals.max_spp_per_grp * Globals.max_rgroups) +#define MAX_SPECIES (SuperGlobals.max_spp_per_grp * SuperGlobals.max_rgroups) #define MAX_SPECIESNAMELEN 4 /* keep around for SOILWAT for now */ /* output_Bmass_Yearly of ST_output.c and _make_header and _make_header_with_std * of ST_stats.c output different numbers of fields. Set MAX_OUTFIELDS to the * maximum number of fields these three functions are capable of outputting. */ -#define MAX_OUTFIELDS ((MAX_SPECIES * 2) + (Globals.max_rgroups * 6) + 8) +#define MAX_OUTFIELDS ((MAX_SPECIES * 2) + (SuperGlobals.max_rgroups * 6) + 8) -#define MAX_FIELDLEN (Globals.max_groupnamelen + 6) /* +6 for xtra chars like _RSize, etc */ +#define MAX_FIELDLEN (SuperGlobals.max_groupnamelen + 6) /* +6 for xtra chars like _RSize, etc */ #define MAX_CELLS 10000 // defines the maximum number of cells in the grid option /* Constants for flagging whether a sort is @@ -114,12 +114,12 @@ typedef enum {F_First, F_Log, F_Model, F_Env, F_Plot, F_RGroup, F_Species, * preferably as GrpIndex, but note that it gets changed, so it * can only be an lvalue. */ /* void ForEachGroup(GrpIndex) */ -#define ForEachGroup(c) for((c)=0; (c)< Globals.grpCount; (c)++) +#define ForEachGroup(c) for((c)=0; (c)< Globals->grpCount; (c)++) /* Generate an SppIndex to access Species[] to loop over each * defined species, irrespective of group. */ /* void ForEachSpecies(SppIndex) */ -#define ForEachSpecies(s) for((s)=0; (s)< Globals.sppCount; (s)++) +#define ForEachSpecies(s) for((s)=0; (s)< Globals->sppCount; (s)++) /* Same for individuals within a species. Traverses a species' * linked list of IndivType objects. i is a pointer to @@ -179,6 +179,7 @@ typedef struct plot_st PlotType; typedef struct globals_st ModelType; typedef struct bmassflags_st BmassFlagsType; typedef struct mortflags_st MortFlagsType; +typedef struct superglobals_st GlobalType; #endif diff --git a/ST_environs.c b/ST_environs.c index 264f1eaa..e339718a 100644 --- a/ST_environs.c +++ b/ST_environs.c @@ -23,7 +23,7 @@ #include "sxw_funcs.h" #include "sw_src/filefuncs.h" #include "sw_src/Times.h" -extern SXW_t SXW; +extern SXW_t* SXW; /*********** Locally Used Function Declarations ************/ /***********************************************************/ @@ -60,28 +60,63 @@ void Env_Generate( void) { _make_disturbance(); } +/* Deep copy one EnvType's information to another. Note that both must be initialized + BEFORE calling this function. */ +void copy_environment(const EnvType* src, EnvType* dest){ + if(!src){ + return; + } + + dest->lyppt = src->lyppt; + dest->ppt = src->ppt; + dest->temp = src->temp; + dest->gsppt = src->gsppt; + dest->temp_reduction[0] = src->temp_reduction[0]; + dest->temp_reduction[1] = src->temp_reduction[1]; + dest->wet_dry = src->wet_dry; +} + +/* Deep copy one PlotType's information to another. Note that both must be initialized + BEFORE calling this function. */ +void copy_plot(const PlotType* src, PlotType* dest){ + if(!src){ + return; + } + + dest->disturbance = src->disturbance; + dest->disturbed = src->disturbed; + dest->pat_removed = src->pat_removed; +} + +/* Deep copy one SucculentType's information to another. Note that both must be initialized + BEFORE calling this function. */ +void copy_succulent(const SucculentType* src, SucculentType* dest){ + if(!src){ + return; + } + + dest->growth[0] = src->growth[0]; + dest->growth[1] = src->growth[1]; + dest->mort[0] = src->mort[0]; + dest->mort[1] = src->mort[1]; + dest->prob_death = src->prob_death; + dest->reduction = src->reduction; +} + /**************************************************************/ static void _make_ppt( void) { /*======================================================*/ /* If not running SOILWAT,take a random number from normal distribution with*/ /* mean, stddev that is between min & max from */ -/* the Globals.ppt structure.*/ -/* Also set the growing season precip. */ +/* the Globals->ppt structure.*/ +/* Also determine growing season precipitation. */ /* HISTORY */ /* Chris Bennett @ LTER-CSU 6/15/2000 */ /* cwb - 6-Dec-02 -- added code to interface with STEPWAT. * The ppt and gsppt are set in _sxw_set_environs() * but we still pass through this code to set the - * Dry/Wet/Normal state. - * KAP 1/26/2017 The above note by CB is not correct. Env.ppt - * is set in _sxw_set_environs, but gsppt is not, it is - * set below. When using SOILWAT or not, the gsspt, ppt.dry, - * and ppt.wet is currently fixed each year and read from env.in - * We should consider calculating gsspt in the _sxw_set_environs - * function when running SOILWAT (so it is not fixed), and allowing - * what constitutes a wet and dry year to vary across sites. */ - + * Dry/Wet/Normal state. */ /*------------------------------------------------------*/ IntS i; @@ -93,27 +128,27 @@ static void _make_ppt( void) { // Run with SOILWAT2: we have monthly PPT and temperature to calculate // growing season precipitation as sum of monthly precipitation of those // months when mean air temperature exceeds a threshold that allows for plant growth 'Globals.temp.gstemp' - Env.gsppt = 0; // gsppt is defined as IntS and units are millimeters + Env->gsppt = 0; // gsppt is defined as IntS and units are millimeters for (i = 0; i < MAX_MONTHS; i++) { - Env.gsppt += GE(SXW.temp_monthly[i], Globals.temp.gstemp) ? - (IntS) (SXW.ppt_monthly[i] * 10. + 0.5) : 0; + Env->gsppt += GE(SXW->temp_monthly[i], Globals->temp.gstemp) ? + (IntS) (SXW->ppt_monthly[i] * 10. + 0.5) : 0; } - if (Env.gsppt <= 0) + if (Env->gsppt <= 0) { LogError(logfp, LOGWARN, "Zero growing season precipitation in "\ - "year = %d of iteration = %d", Globals.currYear, Globals.currIter); - Env.gsppt = 0; + "year = %d of iteration = %d", Globals->currYear, Globals->currIter); + Env->gsppt = 0; } - if ( Env.ppt <= Globals.ppt.dry ) - Env.wet_dry = Ppt_Dry; - else if (Env.ppt >= Globals.ppt.wet) - Env.wet_dry = Ppt_Wet; + if ( Env->ppt <= Globals->ppt.dry ) + Env->wet_dry = Ppt_Dry; + else if (Env->ppt >= Globals->ppt.wet) + Env->wet_dry = Ppt_Wet; else - Env.wet_dry = Ppt_Norm; + Env->wet_dry = Ppt_Norm; } /**************************************************************/ @@ -127,12 +162,12 @@ static void _set_ppt_reduction( void) { /*------------------------------------------------------*/ /* EQN 10*/ - Succulent.reduction = fabs(Succulent.growth[Slope] - * Env.gsppt - + Succulent.growth[Intcpt]); + Succulent->reduction = fabs(Succulent->growth[Slope] + * Env->gsppt + + Succulent->growth[Intcpt]); /* EQN 16*/ - Succulent.prob_death = (Succulent.mort[Slope] * Env.gsppt - + Succulent.mort[Intcpt]) / 100.0; + Succulent->prob_death = (Succulent->mort[Slope] * Env->gsppt + + Succulent->mort[Intcpt]) / 100.0; } /**************************************************************/ @@ -158,20 +193,20 @@ static void _set_temp_reduction( void) { RealF tp[4]; /* parms for temp growth modifier eqn.*/ for ( i=CoolSeason; i <= WarmSeason; i ++ ){ - tp[1] = Globals.tempparm[i][0]; - tp[2] = Globals.tempparm[i][1]; - tp[3] = Globals.tempparm[i][2]; - tp[0] = Env.temp + tp[1]; - Env.temp_reduction[i] = tp[2]*tp[0] + tp[3] * (tp[0]*tp[0]); - Env.temp_reduction[i] = max(0., Env.temp_reduction[i]); + tp[1] = Globals->tempparm[i][0]; + tp[2] = Globals->tempparm[i][1]; + tp[3] = Globals->tempparm[i][2]; + tp[0] = Env->temp + tp[1]; + Env->temp_reduction[i] = tp[2]*tp[0] + tp[3] * (tp[0]*tp[0]); + Env->temp_reduction[i] = max(0., Env->temp_reduction[i]); } - if (Env.temp < 9.5 ) { - Env.temp_reduction[CoolSeason] = .9; - Env.temp_reduction[WarmSeason] = .6; + if (Env->temp < 9.5 ) { + Env->temp_reduction[CoolSeason] = .9; + Env->temp_reduction[WarmSeason] = .6; } else { - Env.temp_reduction[CoolSeason] = .6; - Env.temp_reduction[WarmSeason] = .9; + Env->temp_reduction[CoolSeason] = .6; + Env->temp_reduction[WarmSeason] = .9; } } @@ -191,73 +226,73 @@ static void _make_disturbance( void) { /*------------------------------------------------------*/ /* Can't have simultaneous disturbances*/ - if (Plot.disturbance != NoDisturb) { - switch( Plot.disturbance) { + if (Plot->disturbance != NoDisturb) { + switch( Plot->disturbance) { case FecalPat: - if (Plot.pat_removed) { - Plot.disturbed = 0; - Plot.pat_removed = FALSE; - Plot.disturbance = NoDisturb; + if (Plot->pat_removed) { + Plot->disturbed = 0; + Plot->pat_removed = FALSE; + Plot->disturbance = NoDisturb; } else { - pc = Globals.pat.recol[Slope] * Plot.disturbed - + Globals.pat.recol[Intcpt]; + pc = Globals->pat.recol[Slope] * Plot->disturbed + + Globals->pat.recol[Intcpt]; if (RandUni(&environs_rng) <= pc) { - Plot.pat_removed = TRUE; + Plot->pat_removed = TRUE; /* slight effects for one year*/ - Plot.disturbed = 1; + Plot->disturbed = 1; } else { - Plot.pat_removed = FALSE; - Plot.disturbed++; + Plot->pat_removed = FALSE; + Plot->disturbed++; } } break; case NoDisturb: // Does nothing but prevent a compiler warning case LastDisturb: default: - Plot.disturbed = (Plot.disturbed) ? Plot.disturbed -1 : 0; + Plot->disturbed = (Plot->disturbed) ? (Plot->disturbed - 1) : 0; + break; } - if (Plot.disturbed == 0) - Plot.disturbance = NoDisturb; + if (Plot->disturbed == 0) + Plot->disturbance = NoDisturb; } /* if the disturbance was expired above, */ /* we can generate a new one immediately */ - if (Plot.disturbance == NoDisturb) { + if (Plot->disturbance == NoDisturb) { /* pick some type of disturbance (other than none)*/ event = (DisturbEvent) RandUniIntRange(1, LastDisturb -1, &environs_rng); /* make sure this is off unless needed */ - Plot.pat_removed = FALSE; + Plot->pat_removed = FALSE; switch( event) { case FecalPat: - if (!Globals.pat.use) {event=NoDisturb; break;} - event = (RandUni(&environs_rng) <= Globals.pat.occur) + if (!Globals->pat.use) {event=NoDisturb; break;} + event = (RandUni(&environs_rng) <= Globals->pat.occur) ? event : NoDisturb; if (event == NoDisturb) break; - Plot.pat_removed = (RandUni(&environs_rng) <= Globals.pat.removal) - ? TRUE : FALSE; - Plot.disturbed = 0; + Plot->pat_removed = (RandUni(&environs_rng) <= Globals->pat.removal); + Plot->disturbed = 0; break; case AntMound: - if (!Globals.mound.use) {event=NoDisturb; break;} - event = (RandUni(&environs_rng) <= Globals.mound.occur) + if (!Globals->mound.use) {event=NoDisturb; break;} + event = (RandUni(&environs_rng) <= Globals->mound.occur) ? event :NoDisturb; if (event == NoDisturb) break; - Plot.disturbed = RandUniIntRange(Globals.mound.minyr, - Globals.mound.maxyr, + Plot->disturbed = RandUniIntRange(Globals->mound.minyr, + Globals->mound.maxyr, &environs_rng); break; case Burrow: - if (!Globals.burrow.use) {event=NoDisturb; break;} - event = (RandUni(&environs_rng) <= Globals.burrow.occur) + if (!Globals->burrow.use) {event=NoDisturb; break;} + event = (RandUni(&environs_rng) <= Globals->burrow.occur) ? event :NoDisturb; if (event == NoDisturb) break; - Plot.disturbed = (Globals.burrow.minyr > 0) - ? RandUniIntRange(1, Globals.burrow.minyr, &environs_rng) + Plot->disturbed = (Globals->burrow.minyr > 0) + ? RandUniIntRange(1, Globals->burrow.minyr, &environs_rng) : 0; break; case NoDisturb: @@ -267,7 +302,7 @@ static void _make_disturbance( void) { default: break; } - Plot.disturbance = event; + Plot->disturbance = event; } diff --git a/ST_functions.h b/ST_functions.h index 6d1477b7..a58b1673 100644 --- a/ST_functions.h +++ b/ST_functions.h @@ -18,6 +18,9 @@ #include "ST_defines.h" void Env_Generate( void ); +void copy_environment(const EnvType* src, EnvType* dest); +void copy_plot(const PlotType* src, PlotType* dest); +void copy_succulent(const SucculentType* src, SucculentType* dest); /* See steppe_main.c for declarations of the following diff --git a/ST_globals.h b/ST_globals.h index f8bedbf1..9acea629 100644 --- a/ST_globals.h +++ b/ST_globals.h @@ -21,13 +21,12 @@ extern SpeciesType **Species; extern GroupType **RGroup; -extern SucculentType Succulent; -extern EnvType Env; -extern PlotType Plot; -extern ModelType Globals; +extern SucculentType *Succulent; +extern EnvType *Env; +extern PlotType *Plot; +extern ModelType *Globals; extern BmassFlagsType BmassFlags; extern MortFlagsType MortFlags; +extern GlobalType SuperGlobals; -extern Bool UseSeedDispersal; extern Bool UseGrid; -extern Bool DuringSpinup; diff --git a/ST_grid.c b/ST_grid.c index 6aed8304..b47b8493 100644 --- a/ST_grid.c +++ b/ST_grid.c @@ -1,686 +1,367 @@ -#if 0 - -/********************************************************/ -// Source file: ST_grid.c -// Type: module -// Application: STEPPE - plant community dynamics simulator -// Purpose: This module handles the grid. -// History: -// (5/24/2013) -- INITIAL CODING - DLM -// -// WARNING: This module deals with a LARGE amount of dynamic memory allocation/deallocation (there can be potentially hundreds of thousands of allocations/frees called by this code depending on settings ran). -// Be very wary when editing it as even small changes could possibly cause massive memory errors/leaks to occur. In particular be careful when copy/freeing the linked list of individuals (I would suggest just using the code I wrote for this as it works and it's pretty easy to screw it up). -// Always keep in mind that for every time memory is allocated (every time alloc or calloc is called), a corresponding free is required. I would recommend valgrind or a similar program to debug memory errors as doing it without some kind of tool would be crazy. -/********************************************************/ +/*****************************************************************************/ +// Source file: ST_grid.c +// Type: module +// Application: STEPPE - plant community dynamics simulator +// Purpose: This module performs gridded mode simulations. +// History: +// (5/24/2013) -- INITIAL CODING - DLM +// (March - July 2019) -- Overhauled by Chandler Haukap with Fredrick Pierson +// See issue #262 and pull request #375 on GitHub +/*****************************************************************************/ /* - - ---------------------------------------------------------------------------------------------------------------- - ---------------------------------------------------------------------------------------------------------------- - (DLM) : 7-16-2012 : General notes about this module and why it does certain things (put in the beginning so that they'd be seen) - ---------------------------------------------------------------------------------------------------------------- - ---------------------------------------------------------------------------------------------------------------- - - ---------------------------------------------------------------------------------------------------------------- - the general idea when copying over the dynamically allocated data is (ie. how to deep copy a structure): - ---------------------------------------------------------------------------------------------------------------- - - 1.) Free the dynamically allocated memory (use the _free_head() function to free a linked list of individuals) - 2.) Shallow copy the data (ie. *Species[s] = grid_Species[s][cell])... this will correctly copy all of the data of the structure that isn't a pointer. For the pointers it will simply copy the address (hence why it is a shallow copy). - 3.) Allocate the appropriate amount of memory for the pointers that are being copied to - 4.) Use memcpy to copy the data over to your newly allocated pointer (or use the _copy_head() function to copy the linked list of individuals) - 5.) Be careful at all stages of this process as it is easy to make a simple error that can be very aggravating to try and track down. - - ---------------------------------------------------------------------------------------------------------------- - explanation of why all this trouble is gone through when copying the memory (as it is not obvious by any means): - ---------------------------------------------------------------------------------------------------------------- - - First off, the sizes of all the dynamically allocated memory can be different for every grid cell. To deal with this we free and reallocate memory every time we copy a grid cell. - This also gets around the problem that doing a shallow copy via something like "*Species[s] = grid_Species[s][cell]" would overwrite the address of all the pointers contained within and cause a memory leak if they had already been allocated memory. - The only other way to copy the data would be to individually copy each data member of each structure which would lead to both a much larger code size and code that would break every time a new member is added to any structure in the program while providing likely no performance difference. - It is also important to know what the difference between a shallow copy and a deep copy is. When we are copying over all of these variables, what we want is a deep copy (never to be confused with a shallow copy). - A shallow copy of a structure is when all of the data members are copied over. However, the pointers are treated specially. Instead of copying the data contained within the pointers directly it simply copies the address. - This leaves two pointers that point to the same thing (not what we want) and if the pointer that is copied over was pointing to any memory it would subsequently cause a memory leak. - A deep copy of a structure will copy over all of the data members and copy the memory that the pointers are pointing to (not the addresses). It would be great if C inherently knew how to do this, but it does not. - C's copy constructor cannot know how to do this because it cannot know the length of the pointers. Also, it would be potentially confusing as it would have to allocate memory which would be unexpected. - We must code this behavior in so that we copy over the values held by the pointers into the copy's own separate memory. - - ---------------------------------------------------------------------------------------------------------------- - about performance concerns: - ---------------------------------------------------------------------------------------------------------------- - - This module (ST_grid.c) allocates/deallocates a very large amount of memory. It does so because it must in order to successfully run as desired. - The performance hit of all this memory management is surprisingly low in CPU execution time. Luckily, modern day implementations of malloc/free/memcpy are very fast. - After profiling the code the time spent allocating/deallocating/copying memory is completely negligible compared to the time spent doing calculations. - Where the approach has it's downsides is that the program requires a TON of memory in order to do large simulations (ie. it took around 2.8 GB for a 10,000 cell grid when I tried it). - This shouldn't be an issue in most cases. It is unavoidable though that at some point the number of cells in a simulation will be bounded by the amount of memory available. - Issues could possibly arise if you're trying to run a simulation that requires more memory then your system has available. I don't know of a way to easily check for that condition, so just don't do it. - - ---------------------------------------------------------------------------------------------------------------- - If any of the concepts I have been discussing seem confusing (or your knowledge of pointers feels rusty) I would suggest brushing up on your pointers/memory management. - Some things to go over would be correct free/alloc/memcpy usage (keep in mind that a free is needed for every corresponding alloc call, some people seem not to comprehend that a pointer of pointers (ie. int**) must be freed in multiple steps, otherwise you lose memory), pointer arithmetic, and the difference between arrays & pointers in C. - ---------------------------------------------------------------------------------------------------------------- - (AKT) : 9-7-2015 : Added extra Grid Cell Avg Output file for biomass values - */ -/********************************************************/ - -/* =================================================== */ -/* INCLUDES / DEFINES */ -/* --------------------------------------------------- */ - + Summary: + This module handles the gridded mode of STEPWAT2. To accomplish this we use + a grid of cells represented by the CellType struct. The entire grid of + cells can be referenced by the gridCells variable which is a 2d array of + CellTypes. To allow this module to use the same functions as non-gridded + mode the CellType structs must be loaded into the global variables using + the load_cell function. As long as a cell is loaded in you can be sure that + all functions will work as expected. + +    In addition to all of the functionality of non-gridded mode, gridded mode + has two additional features: initialization and seed dispersal. + Initialization allows vegetation to establish before the simulation + experiments begin. Seed dispersal allows each cell to disperse seeds to + nearby cells. +*/ + +/*******************************************************/ +/* -------------- INCLUDES / DEFINES ----------------- */ +/*******************************************************/ #include -#include #include -#include #include -#include -#include +#include "ST_grid.h" #include "ST_steppe.h" #include "generic.h" #include "filefuncs.h" #include "myMemory.h" #include "ST_globals.h" +#include "ST_stats.h" #include "rands.h" - #include "sxw_funcs.h" -#include "sxw.h" -#include "sxw_vars.h" - -#include "SW_Site.h" -#include "SW_SoilWater.h" -#include "SW_VegProd.h" -#include "SW_Model.h" -#include "SW_Weather.h" -#include "sw_src/pcg/pcg_basic.h" - -/***************** Structure Declarations ******************/ -/***********************************************************/ - -struct _grid_soil_lyr_st -{ // represents a single soil layer - float data[11]; - int width; -}typedef Grid_Soil_Lyr; - -struct _grid_soil_st -{ //represents the input data for all the soil layers of a cell - int num_layers; - char rootsFile[20]; - Grid_Soil_Lyr* lyr; -}typedef Grid_Soil_St; - -struct _grid_disturb_st -{ - int choices[3]; //used as boolean values (ie flags as to whether or not to use the specified disturbance) - int kill_yr, /* kill the group in this year; if 0, don't kill, but see killfreq */ - killfreq_startyr,/* start year for kill frequency*/ - killfrq, /* kill group at this frequency: <1=prob, >1=# years */ - extirp, /* year in which group is extirpated (0==ignore) */ - veg_prod_type, /* type of SOILWAT2 vegetation type: - STEPWAT2 inputs via "rgroup.in" are defined as: 1 for tree, 2 for shrub, 3 for grass, 4 for forb; - however, the inputs get translated by get_SW2_veg_index() to SOILWAT2 values immediately upon reading the inputs (see SW_Defines.h) */ - grazingfreq_startyr,/* start year for grazing frequency*/ - grazing_frq; /* grazing effect on group at this frequency: <1=prob, >1=# years */ - - RealF xgrow; /* ephemeral growth = mm extra ppt * xgrow */ - -}typedef Grid_Disturb_St; - -struct _grid_sd_struct -{ //for seed dispersal - //the idea is that this structure contains all of the cells that the cell represented can possibly disperse seeds to and the probability of the happening for each cell - int size, seeds_present, seeds_received, *cells; //seeds_present && seeds_received are treated as boolean values... cells & prob are to be the length of size - float *prob, lyppt; -}typedef Grid_SD_St; - -struct _grid_sxw_st -{ //holds pointers dynamically allocated by SXW.c - RealD *roots_max, *rootsXphen, *roots_active, *roots_active_rel, - *roots_active_sum, *phen, *prod_bmass, *prod_pctlive; -}typedef Grid_SXW_St; - -struct _grid_init_species_st -{ - int use_SpinUp; - int *species_seed_avail; -}typedef Grid_Init_Species_St; - -/************ Module Variable Declarations ***************/ -/***********************************************************/ - -#define N_GRID_FILES 11 -#define N_GRID_DIRECTORIES 1 +#include "ST_initialization.h" +#include "ST_progressBar.h" +#include "ST_seedDispersal.h" -char *grid_files[N_GRID_FILES], *grid_directories[N_GRID_DIRECTORIES], sd_Sep; +char sd_Sep; -int grid_Cols, grid_Rows, grid_Cells, sd_NYearsSeedsAvailable; -int UseDisturbances, UseSoils, sd_DoOutput, sd_MakeHeader, sd_Option1a, - sd_Option1b, sd_Option2a, sd_Option2b; //these are treated like booleans +int grid_Cells; +Bool UseDisturbances, UseSoils, sd_DoOutput; //these are treated like booleans -// these variables are for storing the globals in STEPPE... they are dynamically allocated/freed -SpeciesType *grid_Species[MAX_SPECIES], *spinup_Species[MAX_SPECIES]; -GroupType *grid_RGroup[MAX_RGROUPS], *spinup_RGroup[MAX_RGROUPS]; -SucculentType *grid_Succulent, *spinup_Succulent; -EnvType *grid_Env, *spinup_Env; -PlotType *grid_Plot, *spinup_Plot; -ModelType *grid_Globals, *spinup_Globals; - -// these two variables are for storing SXW variables... also dynamically allocated/freed -SXW_t *grid_SXW, *spinup_SXW; -Grid_SXW_St *grid_SXW_ptrs, *spinup_SXW_ptrs; +/***************************** Externed variables **********************************/ +/* Note that in an ideal world we wouldn't need to extern any variables because + every module would declare them in a header file. Hopefully we can get this + cleaned up soon! -CH */ // these are SOILWAT variables that we need... extern SW_SOILWAT SW_Soilwat; -extern SW_SITE SW_Site; -extern SW_VEGPROD SW_VegProd; extern SW_WEATHER SW_Weather; -extern pcg32_random_t grid_rng; //this file's unique random number generator - -//This is Rgroup structure pointer that will read rgroup disturbance value, will be used in -// grid disturbance -//extern GroupType *RGroup [MAX_RGROUPS]; // don't need to extern here, because this is done in ST_globals.h - -// these are grids to store the SOILWAT variables... also dynamically allocated/freed -SW_SOILWAT *grid_SW_Soilwat, *spinup_SW_Soilwat; -SW_SITE *grid_SW_Site, *spinup_SW_Site; -SW_VEGPROD *grid_SW_VegProd, *spinup_SW_VegProd; -SW_MODEL *grid_SW_Model, *spinup_SW_Model; - -// these two variables are used to store the soil/distubance inputs for each grid cell... also dynamically allocated/freed -Grid_Soil_St *grid_Soils; -Grid_Disturb_St *grid_Disturb; -Grid_Init_Species_St *grid_initSpecies; -Grid_SD_St *grid_SD[MAX_SPECIES]; //for seed dispersal +extern pcg32_random_t grid_rng; // Gridded mode's unique RNG. -// these variables are used for the soil types in the spinup options -int nSoilTypes, *soilTypes_Array, *grid_SoilTypes; +/* We need to seed these RNGs when using the gridded mode but do not use them in this file. */ +extern pcg32_random_t environs_rng; // Used exclusively in ST_environs.c +extern pcg32_random_t mortality_rng; // Used exclusively in ST_mortality.c +extern pcg32_random_t resgroups_rng; // Used exclusively in ST_resgroups.c +extern pcg32_random_t species_rng; // Used exclusively in ST_species.c +extern pcg32_random_t markov_rng; // Used exclusively in SW_Markov.c -extern Bool UseProgressBar; +extern Bool UseProgressBar; // From ST_main.c +extern Bool* _SomeKillage; // From ST_mortality.c /******** Modular External Function Declarations ***********/ /* -- truly global functions are declared in functions.h --*/ /***********************************************************/ - -// Declare functions defined elsewhere: -void runGrid(void); //to be called from ST_main.c -void _kill_annuals(void); -void _kill_extra_growth(void); -void rgroup_Extirpate(GrpIndex rg); - -/************* External Function Declarations **************/ -/***********************************************************/ +//from ST_species.c +void proportion_Recovery(void); +void save_annual_species_relsize(void); +void copy_species(const SpeciesType* src, SpeciesType* dest); //from ST_resgroups.c void rgroup_Grow(void); void rgroup_Establish(void); void rgroup_IncrAges(void); void rgroup_PartResources(void); -//void rgroup_ResPartIndiv(void); +void copy_rgroup(const GroupType* src, GroupType* dest); //from ST_mortality.c void mort_Main(Bool *killed); void mort_EndOfYear(void); +void grazing_EndOfYear(void); +void _kill_annuals(void); +void _kill_maxage(void); +void _kill_extra_growth(void); //functions from ST_params.c void parm_Initialize(void); void parm_SetFirstName(char *s); void parm_SetName(char *s, int which); void parm_free_memory(void); +void files_init(void); +void maxrgroupspecies_init(void); //from ST_main.c void Plot_Initialize(void); +void deallocate_Globals(Bool isGriddedMode); -//functions from ST_stats.c -void stat_Collect(Int year); -void stat_Collect_GMort(void); -void stat_Collect_SMort(void); -void stat_Output_AllMorts(void); -void stat_Output_AllBmass(void); -//Adding functions for creating grid cells avg values output file -void stat_Output_AllBmassAvg(void); -void stat_Output_AllCellAvgBmass(const char * filename); -void stat_Output_Seed_Dispersal(const char * filename, const char sep, - Bool makeHeader); -void stat_Load_Accumulators(int cell, int year); -void stat_Save_Accumulators(int cell, int year); -void stat_Free_Accumulators(void); -void stat_Init_Accumulators(void); - -//functions from sxw.c -//void free_sxw_memory( void ); -//void free_all_sxw_memory(void); -void load_sxw_memory(RealD * grid_roots_max, RealD* grid_rootsXphen, - RealD* grid_roots_active, RealD* grid_roots_active_rel, - RealD* grid_roots_active_sum, RealD* grid_phen, RealD* grid_prod_bmass, - RealD* grid_prod_pctlive); -void save_sxw_memory(RealD * grid_roots_max, RealD* grid_rootsXphen, - RealD* grid_roots_active, RealD* grid_roots_active_rel, - RealD* grid_roots_active_sum, RealD* grid_phen, RealD* grid_prod_bmass, - RealD* grid_prod_pctlive); -//void SXW_init( Bool init_SW ); - - -/*********** Locally Used Function Declarations ************/ -/***********************************************************/ +/* Functions from sxw.c */ +SXW_t* getSXW(void); +SXW_resourceType* getSXWResources(void); +transp_t* getTranspWindow(void); +void copy_sxw_variables(SXW_t* newSXW, SXW_resourceType* newSXWResources, transp_t* newTransp_window); -static int _load_bar(char* prefix, clock_t start, int x, int n, int r, int w); -static double _time_remaining(clock_t start, char* timeChar, double percentDone); -static void _run_spinup(void); +/***********************************************************/ +/* --------- Locally Used Function Declarations ---------- */ +/***********************************************************/ +void _copy_soils(SoilType* src, SoilType* dest); +static void printGeneralInfo(void); static void _init_grid_files(void); -static void _init_grid_inputs(void); static void _init_SXW_inputs(Bool init_SW, char *f_roots); -static void _init_stepwat_inputs(void); -static void _init_grid_globals(void); -static void _init_spinup_globals(void); -static void _load_grid_globals(void); -static void _load_spinup_globals(void); -static void _free_grid_memory(void); -static void _free_spinup_memory(void); -static void _free_grid_globals(void); -static void _free_spinup_globals(void); -static void _load_cell(int row, int col, int year, Bool useAccumulators); -static void _load_spinup_cell(int cell); -static void _save_cell(int row, int col, int year, Bool useAccumulators); -static void _save_spinup_cell(int cell); +static void _allocate_gridCells(int rows, int cols); +static void _Output_AllCellAvgBmass(const char* filename); +static void _Output_AllCellAvgMort(const char* filename); +static void _allocate_accumulators(void); static void _read_disturbances_in(void); static void _read_soils_in(void); -static void _init_soil_layers(int cell, int isSpinup); -static float _read_a_float(FILE *f, char *buf, const char *filename, - const char *descriptor); -static float _cell_dist(int row1, int row2, int col1, int col2, float cellLen); -static void _read_seed_dispersal_in(void); -static void _do_seed_dispersal(void); -static void _set_sd_lyppt(int row, int col); -static void _kill_groups_and_species(void); -static int _do_grid_disturbances(int row, int col); +static int _read_soil_line(char* buf, SoilType* destination, int layer); static void _read_init_species(void); -static void _do_groups_and_species_extirpate(void); -static void _do_grid_proportion_Recovery(int row, int col); -static void _do_grid_grazing_EndOfYear(int row, int col); - -//static void _copy_species(SpeciesType* to, SpeciesType* from, Bool deep); - -static IndivType* _create_empty_indv(void); //these 5 functions are used for copying/freeing the linked list of individuals correctly... -static void _free_individuals(IndivType *head); -static void _free_head(IndivType *head); -static IndivType* _copy_individuals(IndivType *head); -static IndivType* _copy_head(IndivType *head); +static void _read_maxrgroupspecies(void); +static void _read_grid_setup(void); +static void _read_files(void); +static void _init_stepwat_inputs(void); +static void _init_grid_inputs(void); /******************** Begin Model Code *********************/ /***********************************************************/ -/***********************************************************/ -double _time_remaining(clock_t start, char* timeChar, double percentDone) -{ - // for use in _load_bar() function... pretty much it returns the amount of time left and a character in timeChar representing the units - // percent done must be from 0 to 1, with 0 representing no work done (0%) and 1 representing all of the work done (ie 100%) - clock_t timeElapsed = clock() - start; //gets the time since we started (this is in CPU cycles). We convert to seconds in the next part - double result = (((double) timeElapsed) / CLOCKS_PER_SEC) / percentDone - * (1.0 - percentDone); //gets estimated time left until the work is complete based upon timeElapsed and percentDone - - *timeChar = 's'; //get the biggest time units that we can use (ie no use displaying 120 seconds if we can display 2 minutes) - if (result > 60) - { - result /= 60.0; - *timeChar = 'm'; - if (result > 60) - { - result /= 60.0; - *timeChar = 'h'; - if (result > 24) - { - result /= 24.0; - *timeChar = 'd'; - if (result > 7) - { - result /= 7.0; - *timeChar = 'w'; - } - } - } - } - - return result; -} - -/***********************************************************/ -static int _load_bar(char* prefix, clock_t start, int x, int n, int r, int w) -{ - //loads a progress bar, x is how much progress has been made, n is how much progress to be done, r is how many times to update, and w is width of the progress bar - //wouldn't suggest using this if your stdout is being redirected somewhere else (it doesn't work right in that case and gives unwanted output) - //gotten from: http://www.rosshemsley.co.uk/2011/02/creating-a-progress-bar-in-c-or-any-other-console-app/ - - //modified to include an estimate of the time remaining... start must be a clock started (using clock() function) right before beginning the work - - // Only update r times. - if (x % (n / r) != 0) - return (int) ((x / (float) n) * 100); - - int i; - - printf("\r"); //we output a carriage-return character to put us back at the beginning of the line - if (prefix != NULL) - printf("%s", prefix); - - // Calculuate the ratio of complete-to-incomplete. - float ratio = x / (float) n; - int c = ratio * w; - int result = (int) (ratio * 100); - - if (result > 1) - { //we don't give an estimate if less than 2% of the work is complete because we don't have any data to go off of... - char timeChar; - double timeLeft = _time_remaining(start, &timeChar, (double) ratio); - if (timeLeft < 10) - printf("(est 0%.2f%c) ", timeLeft, timeChar); - else - printf("(est %.2f%c) ", timeLeft, timeChar); - } - - // Show the percentage complete. - printf("%3d%% [", (int) (ratio * 100)); - - // Show the load bar. - for (i = 0; i < c; i++) - printf("="); - - for (i = c; i < w; i++) - printf(" "); - - printf("]"); - fflush(stdout); //we do this to flush (ie. print) the output, since stdout typically waits for a newline character before flushing - return result; +/* Print information about the simulation to stdout. */ +static void printGeneralInfo(void){ + /* ------------------- Print some general information to stdout ----------------------- */ + printf("Number of iterations: %d\n", SuperGlobals.runModelIterations); + printf("Number of years: %d\n", SuperGlobals.runModelYears); + printf("Number of cells: %d\n\n", grid_Cells); + if(UseDisturbances) printf("Using grid disturbances file\n"); + if(UseSoils) printf("Using grid soils file\n"); + if(initializationMethod == INIT_WITH_SEEDS){ + printf("Running seed dispersal as initialization\n"); + } else if(initializationMethod == INIT_WITH_SPINUP) { + printf("Running Spinup as initialization\n"); + } + if(initializationMethod != INIT_WITH_NOTHING){ + printf("Number of initialization years: %d\n", SuperGlobals.runInitializationYears); + } + if(UseSeedDispersal){ + printf("Dispersing seeds between cells\n"); + } + printf("\n"); + /* --------------------------- END printing general info -------------------------------- */ } -/***********************************************************/ +/* Run gridded mode. */ void runGrid(void) { - // this function sets up & runs the grid + int i, j; + Bool killedany; + IntS year, iter; _init_grid_files(); // reads in files.in file - _init_stepwat_inputs(); // reads the stepwat inputs in + _read_maxrgroupspecies(); // reads in maxrgroupspecies.in file + _read_grid_setup(); // reads in grid_setup.in file + _read_files(); // reads in Stepwat_Inputs/files.in file + _init_stepwat_inputs(); // reads the stepwat inputs in + _init_grid_inputs(); // reads the grid inputs in & initializes the global grid variables //SWC hist file prefix needs to be cleared Mem_Free(SW_Soilwat.hist.file_prefix); SW_Soilwat.hist.file_prefix = NULL; - _init_grid_inputs();// reads the grid inputs in & initializes the global grid variables - if (sd_Option2a || sd_Option2b) - _run_spinup(); // does the initial spinup + printGeneralInfo(); - double prog_Percent = 0.0, prog_Incr, prog_Acc = 0.0; - char prog_Prefix[32]; - clock_t prog_Time; - int i, j; - Bool killedany; - IntS year, iter; - if (UseProgressBar) - { - prog_Incr = (((double) 1) - / ((double) ((Globals.runModelYears * grid_Cells) - * Globals.runModelIterations))); //gets how much progress we'll make in one year towards our goal of iter*years*cells - prog_Time = clock(); //used for timing - sprintf(prog_Prefix, "simulations: "); + if(initializationMethod != INIT_WITH_NOTHING){ + runInitialization(); + } else { + /* SXW expects to be run from the testing.sagebrush.master/Stepwat_Inputs directory. + However, we are running from the testing.sagebrush.master directory. To find the + location of the SOILWAT input files we need to manually set SXW->f_watin. */ + ChDir(grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS]); + SXW_Reset(gridCells[0][0].mySXW->f_watin); + ChDir(".."); } - char aString[2048]; - sprintf(aString, "%s/%s", grid_directories[0], SW_Weather.name_prefix); + // SOILWAT resets SW_Weather.name_prefix every iteration. This is not the behavior we want + // so the name is stored here. + char SW_prefix_permanent[2048]; + sprintf(SW_prefix_permanent, "%s/%s", grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS], SW_Weather.name_prefix); - for (iter = 1; iter <= Globals.runModelIterations; iter++) + for (iter = 1; iter <= SuperGlobals.runModelIterations; iter++) { //for each iteration /* * 06/15/2016 (akt) Added resetting correct historical weather file path, * as it was resetting to original path value (that was not correct for grid version)from input file after every iteration */ - sprintf(SW_Weather.name_prefix, "%s", aString); //updates the directory correctly for the weather files so soilwat can find them - - if (BmassFlags.yearly || MortFlags.yearly) - parm_Initialize(); + sprintf(SW_Weather.name_prefix, "%s", SW_prefix_permanent); //updates the directory of the weather files so SOILWAT2 can find them + + // Initialize the plot for each grid cell + for (i = 0; i < grid_Rows; i++){ + for (j = 0; j < grid_Cols; j++){ + load_cell(i, j); + Plot_Initialize(); + Globals->currIter = iter; + } + } + unload_cell(); // Reset the global variables - Plot_Initialize(); - if (iter > 1) - _free_grid_globals(); //frees the memory from when we called _load_grid_globals() last time... (doesn't need to be called on the first iteration because the memory hasn't been allocated yet) + // If we used spinup we need to reset to the state of the program right after spinup. + if (initializationMethod == INIT_WITH_SPINUP){ + loadInitializationConditions(); + } - Globals.currIter = iter; - _load_grid_globals(); //allocates/initializes grid variables (specifically the ones that are going to change every iter) + RandSeed(SuperGlobals.randseed, &environs_rng); + RandSeed(SuperGlobals.randseed, &mortality_rng); + RandSeed(SuperGlobals.randseed, &resgroups_rng); + RandSeed(SuperGlobals.randseed, &species_rng); + RandSeed(SuperGlobals.randseed, &grid_rng); + RandSeed(SuperGlobals.randseed, &markov_rng); - for (year = 1; year <= Globals.runModelYears; year++) + for (year = 1; year <= SuperGlobals.runModelYears; year++) { //for each year - for (i = 1; i <= grid_Rows; i++) - for (j = 1; j <= grid_Cols; j++) + if(UseProgressBar){ + logProgress(iter, year, SIMULATION); + } + for (i = 0; i < grid_Rows; i++){ + for (j = 0; j < grid_Cols; j++) { //for each cell + + /* Ensure that all global variables reference the specific cell */ + load_cell(i, j); - //fprintf(stderr, "year: %d", year); - _load_cell(i, j, year, TRUE); - - if (year == 1 && (sd_Option2a || sd_Option2b)) - { - //TODO: DM finish this... + Globals->currYear = year; - int cell = j + ((i - 1) * grid_Cols) - 1; // converts the row/col into an array index - int spinup_cell = grid_SoilTypes[cell]; // gets us the actual cell we want to load up from the spinup - - if ((sd_Option2b && grid_initSpecies[cell].use_SpinUp) - || sd_Option2a) - _load_spinup_cell(spinup_cell); // loads the spinup cell into the global variables + /* Seed dispersal needs to take into account last year's precipitation, + so we'll record it before calling Env_Generate(). */ + if (year > 1 && UseSeedDispersal){ + gridCells[i][j].mySeedDispersal->lyppt = gridCells[i][j].myEnvironment.ppt; } - Globals.currYear = year; - - if (year > 1 && UseSeedDispersal) - _set_sd_lyppt(i, j); - - + /* The following functions mimic ST_main.c. */ - rgroup_Establish(); /* excludes annuals */ + rgroup_Establish(); // Establish individuals. - Env_Generate(); //calls : SXW_Run_SOILWAT() which calls : _sxw_sw_run() which calls : SW_CTL_run_current_year() + Env_Generate(); // Run SOILWAT2 to generate resources. - rgroup_PartResources(); - rgroup_Grow(); + rgroup_PartResources(); // Distribute resources + rgroup_Grow(); // Implement plant growth - mort_Main(&killedany); + mort_Main(&killedany); // Mortality that occurs during the growing season - rgroup_IncrAges(); + rgroup_IncrAges(); // Increment ages of all plants - // Added functions for Grazing and mort_end_year as proportional killing effect before exporting biomass end of the year - _do_grid_grazing_EndOfYear(i, j); - _do_grid_disturbances(i, j); + grazing_EndOfYear(); // Livestock grazing + + save_annual_species_relsize(); // Save annuals before we kill them - stat_Collect(year); + mort_EndOfYear(); // End of year mortality. - _save_cell(i, j, year, TRUE); + stat_Collect(year); // Update the accumulators - // Moved kill annual and kill extra growth after we export biomass, we also doing recoverly after killing year - _kill_annuals(); - _do_grid_proportion_Recovery(i, j); - _kill_extra_growth(); + _kill_annuals(); // Kill annuals + _kill_maxage(); // Kill plants that reach max age + proportion_Recovery(); // Recover from any disturbances + _kill_extra_growth(); // Kill superfluous growth - if (UseProgressBar) - { - prog_Percent += prog_Incr; //updating our percent done - if (prog_Percent > prog_Acc) - { //only update if 1% progress or more has been made since the last time we updated (this check is so it doesn't waste processing time that could be spent running the simulations by updating all of the time) - prog_Acc += 0.01; - _load_bar(prog_Prefix, prog_Time, - (int) (100 * prog_Percent), 100, 100, 10); //display our bar to the console - } - } } /* end model run for this cell*/ - - if (UseSeedDispersal) - _do_seed_dispersal(); + } /* end model run for this row */ + if (UseSeedDispersal){ + disperseSeeds(); + } + + unload_cell(); // Reset the global variables }/* end model run for this year*/ - // collects the data appropriately for the mort output... (ie. fills the accumulators in ST_stats.c with the values that they need) - if (MortFlags.summary) - for (i = 1; i <= grid_Rows; i++) - for (j = 1; j <= grid_Cols; j++) + // collects the data for the mort output, + // i.e. fills the accumulators in ST_stats.c. + if (MortFlags.summary){ + for (i = 0; i < grid_Rows; i++){ + for (j = 0; j < grid_Cols; j++) { - _load_cell(i, j, Globals.runModelYears, TRUE); + load_cell(i, j); stat_Collect_GMort(); stat_Collect_SMort(); - _save_cell(i, j, Globals.runModelYears, TRUE); } + } + } + unload_cell(); //reset soilwat to initial condition - ChDir(grid_directories[0]); - SXW_Reset(); + ChDir(grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS]); + for(i = 0; i < grid_Rows; ++i){ + for(j = 0; j < grid_Cols; ++j){ + load_cell(i, j); + SXW_Reset(gridCells[i][j].mySXW->f_watin); + unload_cell(); + } + } Mem_Free(SW_Soilwat.hist.file_prefix); SW_Soilwat.hist.file_prefix = NULL; ChDir(".."); - } /*end iterations */ - - if (UseProgressBar) - printf("\rsimulations took approximately: %.2f seconds\n", - ((double) (clock() - prog_Time) / CLOCKS_PER_SEC)); + } /* end iterations */ - if (UseProgressBar) - { - prog_Percent = prog_Acc = 0.0; - prog_Incr = ((double) 1) / ((double) grid_Cells); - prog_Time = clock(); - sprintf(prog_Prefix, "outputting: "); + if(UseProgressBar){ + logProgress(0, 0, OUTPUT); } - // outputs all of the mort and BMass files for each cell... - for (i = 1; i <= grid_Rows; i++) - for (j = 1; j <= grid_Cols; j++) + // Output all of the mort and BMass files for each cell. + for (i = 0; i < grid_Rows; i++){ + for (j = 0; j < grid_Cols; j++) { - - int cell = j + ((i - 1) * grid_Cols) - 1; - _load_cell(i, j, 1, TRUE); - for (year = 2; year <= Globals.runModelYears; year++) // _load_cell gets the first years accumulators loaded, so we start at 2... - stat_Load_Accumulators(cell, year); - + int cell = j + (i * grid_Cols); + load_cell(i, j); char fileMort[1024], fileBMass[1024], fileReceivedProb[1024]; - sprintf(fileReceivedProb, "%s%d.csv", grid_files[9], cell); - sprintf(fileMort, "%s%d.csv", grid_files[8], cell); - sprintf(fileBMass, "%s%d.csv", grid_files[7], cell); + sprintf(fileReceivedProb, "%s%d.csv", grid_files[GRID_FILE_PREFIX_RECEIVEDPROB], cell); + sprintf(fileMort, "%s%d.csv", grid_files[GRID_FILE_PREFIX_MORTAVG], cell); + sprintf(fileBMass, "%s%d.csv", grid_files[GRID_FILE_PREFIX_BMASSAVG], cell); parm_SetName(fileMort, F_MortAvg); parm_SetName(fileBMass, F_BMassAvg); - if (MortFlags.summary) + if (MortFlags.summary && writeIndividualFiles){ stat_Output_AllMorts(); - if (BmassFlags.summary) - stat_Output_AllBmassAvg(); - if (UseSeedDispersal && sd_DoOutput) - stat_Output_Seed_Dispersal(fileReceivedProb, sd_Sep, - sd_MakeHeader); - - if (UseProgressBar) - { - prog_Percent += prog_Incr; - if (prog_Percent > prog_Acc) - { - prog_Acc += 0.01; - _load_bar(prog_Prefix, prog_Time, 100 * prog_Percent, 100, - 100, 10); - } } - + if (BmassFlags.summary && writeIndividualFiles){ + stat_Output_AllBmass(); + } + if (UseSeedDispersal && sd_DoOutput && writeIndividualFiles){ + stat_Output_Seed_Dispersal(fileReceivedProb, sd_Sep); + } } - //Here creating grid cells avg values output file - char fileBMassCellAvg[1024]; - sprintf(fileBMassCellAvg, "%s.csv", grid_files[10]); - if (BmassFlags.summary) - stat_Output_AllCellAvgBmass(fileBMassCellAvg); - - if (UseProgressBar) - printf("\routputting files took approximately %.2f seconds\n", - ((double) (clock() - prog_Time) / CLOCKS_PER_SEC)); - _free_grid_memory(); // free our allocated memory since we do not need it anymore - /*if(UseProgressBar)*/printf("!\n"); -} - -/***********************************************************/ -static void _run_spinup(void) -{ - - //does the spinup, it's pretty much like running the grid, except some differences like no seed dispersal and no need to deal with output accumulators - - int i, spinup_Cell; - Bool killedany; - IntS year, iter; - - DuringSpinup = TRUE; - - if (!UseSoils) - { // if we're not using inputting soils then there is simply one soil type as all the soils are the same - nSoilTypes = 1; - soilTypes_Array[0] = 0; - for (i = 0; i < grid_Cells; i++) - grid_SoilTypes[i] = 0; } + unload_cell(); // Reset the global variables - _init_spinup_globals(); - _load_spinup_globals(); - - for (iter = 1; iter <= 1; iter++) - { //for each iteration... only 1 iteration allowed for now - - if (BmassFlags.yearly || MortFlags.yearly) - parm_Initialize(); - - Plot_Initialize(); - - Globals.currIter = iter; - //_load_grid_globals(); //allocates/initializes grid variables (specifically the ones that are going to change every iter) - - for (year = 1; year <= Globals.runModelYears; year++) - { //for each year - for (spinup_Cell = 0; spinup_Cell < nSoilTypes; spinup_Cell++) - { // for each different soil type - - //int cell = soilTypes_Array[spinup_Cell]; // this is the first cell of this soiltypes actual cell number - //int j = cell % grid_Cols + 1; // this is the column of the first cell of this soiltype - //int i = ((cell + 1 - j) / grid_Cols) + 1; // this is the row of the first cell of this soiltype - - _load_spinup_cell(spinup_Cell); - Globals.currYear = year; - - // _do_grid_disturbances(i, j); - - rgroup_Establish(); /* excludes annuals */ - - Env_Generate(); //calls : SXW_Run_SOILWAT() which calls : _sxw_sw_run() which calls : SW_CTL_run_current_year() - - rgroup_PartResources(); - rgroup_Grow(); - - mort_Main(&killedany); - - rgroup_IncrAges(); - - stat_Collect(year); - //mort_EndOfYear(); - _save_spinup_cell(spinup_Cell); - - _kill_annuals(); - _kill_extra_growth(); - - } /* end model run for this cell*/ - - }/* end model run for this year*/ - - ChDir(grid_directories[0]); - SXW_Reset(); - //TODO: This is a shortcut. swc history is not used and shouldn't be until this is fixed. - Mem_Free(SW_Soilwat.hist.file_prefix); - SW_Soilwat.hist.file_prefix = NULL; - ChDir(".."); - //_free_grid_globals(); //free's the grid variables that change every iter - } /*end iterations */ + // Output the Bmass and Mort average statistics (if requested). + char fileBMassCellAvg[1024], fileMortCellAvg[1024]; + if (BmassFlags.summary){ + sprintf(fileBMassCellAvg, "%s.csv", grid_files[GRID_FILE_PREFIX_BMASSCELLAVG]); + _Output_AllCellAvgBmass(fileBMassCellAvg); + } + if (MortFlags.summary){ + sprintf(fileMortCellAvg, "%s.csv", grid_files[GRID_FILE_PREFIX_MORTCELLAVG]); + _Output_AllCellAvgMort(fileMortCellAvg); + } - DuringSpinup = FALSE; + free_grid_memory(); // Free our allocated memory since we do not need it anymore + parm_free_memory(); // Free memory allocated to the _files array in ST_params.c + if(initializationMethod == INIT_WITH_SPINUP) { + freeInitializationMemory(); + } + logProgress(0, 0, DONE); } -/***********************************************************/ +/* Read the files.in file which was supplied to the program as an argument. + This function saves the file names it reads to grid_files and grid_directories. */ static void _init_grid_files(void) { // reads the files.in file - FILE *f; char buf[1024]; int i; @@ -706,2357 +387,1203 @@ static void _init_grid_files(void) LogError(stderr, LOGFATAL, "Invalid files.in"); // opens the log file... - if (!strcmp("stdout", grid_files[0])) - logfp = stdout; - else - logfp = OpenFile(grid_files[0], "w"); //grid_files[0] is the logfile to use - - /*printf("stepwat dir: %s\n", grid_directories[0]); - for(i = 0; i < N_GRID_FILES; i++) - printf("%d : %s\n", i, grid_files[i]);*/ + if (!strcmp("stdout", grid_files[GRID_FILE_LOGFILE])){ + logfp = stdout; + } + else { + logfp = OpenFile(grid_files[GRID_FILE_LOGFILE], "w"); + } CloseFile(&f); } -/***********************************************************/ +/* Read all gridded mode files excluding grid_setup.in. This function overrided values specified in non-gridded + mode files, so make sure you have read the non-gridded mode files before calling this function.*/ static void _init_grid_inputs(void) { - // reads in the grid input file - - FILE *f; - char buf[1024]; - int i, j; - - f = OpenFile(grid_files[1], "r"); //grid_files[1] is the grid inputs file - - GetALine(f, buf); - i = sscanf(buf, "%d %d", &grid_Rows, &grid_Cols); - if (i != 2) - LogError(logfp, LOGFATAL, - "Invalid grid setup file (rows/cols line wrong)"); - - grid_Cells = grid_Cols * grid_Rows; + int i, j; - if (grid_Cells > MAX_CELLS) - LogError(logfp, LOGFATAL, - "Number of cells in grid exceeds MAX_CELLS defined in ST_defines.h"); - - Globals.nCells = (grid_Cols * grid_Rows); - - GetALine(f, buf); - i = sscanf(buf, "%d", &UseDisturbances); - if (i != 1) - LogError(logfp, LOGFATAL, - "Invalid grid setup file (disturbances line wrong)"); - - GetALine(f, buf); - i = sscanf(buf, "%d", &UseSoils); - if (i != 1) - LogError(logfp, LOGFATAL, "Invalid grid setup file (soils line wrong)"); - - GetALine(f, buf); - i = sscanf(buf, "%d", &j); - if (i != 1) - LogError(logfp, LOGFATAL, - "Invalid grid setup file (seed dispersal line wrong)"); - UseSeedDispersal = itob(j); - - CloseFile(&f); - - _init_grid_globals(); // initializes the global grid variables - if (UseDisturbances) + if (UseDisturbances){ _read_disturbances_in(); - if (UseSeedDispersal) + } + if (UseSeedDispersal || initializationMethod == INIT_WITH_SEEDS) { - _read_seed_dispersal_in(); + initDispersalParameters(); + } + if(initializationMethod != INIT_WITH_NOTHING){ _read_init_species(); } - if (UseSoils) + if (UseSoils) { _read_soils_in(); + } - DuringSpinup = FALSE; + for(i = 0; i < grid_Rows; ++i) { + for(j = 0; j < grid_Cols; ++j) { + load_cell(i, j); + gridCells[i][j].DuringInitialization = FALSE; + } + } + unload_cell(); } -/***********************************************************/ +/* Read SXW input files */ static void _init_SXW_inputs(Bool init_SW, char *f_roots) { SXW_Init(init_SW, f_roots); // initializes soilwat - if (init_SW == TRUE) + if (init_SW) { char aString[2048]; - sprintf(aString, "%s/%s", grid_directories[0], SW_Weather.name_prefix); + sprintf(aString, "%s/%s", grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS], SW_Weather.name_prefix); sprintf(SW_Weather.name_prefix, "%s", aString); //updates the directory correctly for the weather files so soilwat can find them } } -/***********************************************************/ +/* Read in the STEPWAT2 files and populate the grid. This only needs to be called once. + DEPENDENCIES: gridCells must be allocated first. */ static void _init_stepwat_inputs(void) { - // reads in the stepwat inputs - ChDir(grid_directories[0]); // changes to the folder that the stepwat input is in + int i, j; // Used as indices in gridCells + + ChDir(grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS]); // Change to folder with STEPWAT files + parm_SetFirstName(grid_files[GRID_FILE_FILES]); // Set the name of the STEPWAT "files.in" file + + /* Loop through all gridCells. */ + for(i = 0; i < grid_Rows; ++i){ + for(j = 0; j < grid_Cols; ++j){ + load_cell(i, j); // Load this cell into the global variables + parm_Initialize(); // Initialize the STEPWAT variables + gridCells[i][j].myGroup = RGroup; // This is necessary because load_cell only points RGroup to our cell-specific + // resource group array, not to the variable that points to that array. + gridCells[i][j].mySpecies = Species; // This is necessary because load_cell only points Species to our cell-specific + // species array, not to the variable that points to that array. + _init_SXW_inputs(TRUE, NULL); // Initialize the SXW and SOILWAT variables + + // Set mySXW to the location of the newly allocated SXW + gridCells[i][j].mySXW = getSXW(); + // Set myTranspWindow to the location of the newly allocated transp window + gridCells[i][j].myTranspWindow = getTranspWindow(); + // Set mySXWResources to the location of the newly allocated SXW resources + gridCells[i][j].mySXWResources = getSXWResources(); + } /* End for each column */ + } /* End for each row */ + unload_cell(); // Reset the global variables + + /* Since the accumulators used in ST_stats.c are local, we need to allocate our accumulators in ST_grid. + The other option is to create get functions for every accumulator, which is what we do for SXW variables. + The reason we do not do this for accumulators is the sheer number of accumulators, which would require + 14 get functions (as of 4/5/19). */ + _allocate_accumulators(); + + ChDir(".."); // go back to the folder we started in +} + +/* Reread input files. Be careful because this function reallocates the grid. + Make sure you call free_grid_memory before calling this function. */ +void rereadInputs(void){ + _read_grid_setup(); + _read_files(); + _init_stepwat_inputs(); + _init_grid_inputs(); +} - parm_SetFirstName(grid_files[6]);// correctly sets the name of the stepwat files.in file - parm_Initialize(); // loads stepwat input files +/* Allocates memory for the grid cells. This only needs to be called once. */ +static void _allocate_gridCells(int rows, int cols){ + int i, j; + gridCells = (CellType**) Mem_Calloc(rows, sizeof(CellType*), "_allocate_gridCells: rows"); + for(i = 0; i < rows; ++i){ + gridCells[i] = (CellType*) Mem_Calloc(cols, sizeof(CellType), "_allocate_gridCells: columns"); + } - _init_SXW_inputs(TRUE, NULL); + /* Allocate all fields specific to gridded mode. This is not necessary for fields like mySpecies + since they are allocated elsewhere in the code.*/ + for(i = 0; i < grid_Rows; ++i){ + for(j = 0; j < grid_Cols; ++j){ + // shouldBeInitialized is a dynamically allocated array + gridCells[i][j].mySpeciesInit.shouldBeInitialized = (int*) + Mem_Calloc(MAX_SPECIES, sizeof(int), "_allocate_gridCells: mySpeciesInit"); - ChDir(".."); // goes back to the folder that we were in + gridCells[i][j].someKillage = (Bool*) Mem_Calloc(1, sizeof(Bool), "_allocate_gridCells: someKillage"); + } + } } -/***********************************************************/ -static IndivType* _create_empty_indv(void) -{ - //simply allocates memory for an individual and returns the pointer to it +/* Initialize each gridCell's accumulators. + Must be called after STEPWAT inputs have been read. */ +static void _allocate_accumulators(void){ + int i, j; + SppIndex sp; + GrpIndex rg; - return Mem_Calloc(1, sizeof(IndivType), "_create_empty_indv()"); + /* Iterate across all cells */ + for(i = 0; i < grid_Rows; ++i){ + for(j = 0; j < grid_Cols; ++j){ + /* load_cell is not necessary for the actual accumulators, but it is necessary for + the ForEach loops. We still have to refer to the accumulators as + gridCells[i][j]. because the ST_stats accumulators are local. */ + load_cell(i,j); + + if (BmassFlags.dist) { + gridCells[i][j]._Dist = (StatType*) Mem_Calloc(1, sizeof(StatType), "_allocate_accumulators(Dist)"); + gridCells[i][j]._Dist->s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Dist)"); + } + if (BmassFlags.ppt) { + gridCells[i][j]._Ppt = (StatType*) Mem_Calloc(1, sizeof(StatType), "_allocate_accumulators(PPT"); + gridCells[i][j]._Ppt->s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(PPT)"); + } + if (BmassFlags.tmp) { + gridCells[i][j]._Temp = (StatType*) Mem_Calloc(1, sizeof(StatType), "_allocate_accumulators(Temp)"); + gridCells[i][j]._Temp->s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Temp)"); + } + if (BmassFlags.grpb) { + gridCells[i][j]._Grp = (struct stat_st *) + Mem_Calloc( Globals->grpCount, + sizeof(struct stat_st), + "_allocate_accumulators(Grp)"); + ForEachGroup(rg){ + gridCells[i][j]._Grp[rg].s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Grp[rg].s)"); + } -} + if (BmassFlags.size) { + gridCells[i][j]._Gsize = (struct stat_st *) + Mem_Calloc( Globals->grpCount, + sizeof(struct stat_st), + "_allocate_accumulators(GSize)"); + ForEachGroup(rg){ + gridCells[i][j]._Gsize[rg].s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(GSize[rg].s)"); + } + } + + if (BmassFlags.pr) { + gridCells[i][j]._Gpr = (struct stat_st *) + Mem_Calloc( Globals->grpCount, + sizeof(struct stat_st), + "_allocate_accumulators(Gpr)"); + ForEachGroup(rg){ + gridCells[i][j]._Gpr[rg].s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Gpr[rg].s)"); + } + } + + if (BmassFlags.wildfire || BmassFlags.prescribedfire) { + gridCells[i][j]._Gwf = (struct fire_st *) + Mem_Calloc( 1, sizeof(struct fire_st), + "_allocate_accumulators(Gwf)"); + + gridCells[i][j]._Gwf->wildfire = (int *) Mem_Calloc( 1, + sizeof(int) * SuperGlobals.runModelYears, + "_allocate_accumulators(Gwf->wildfire)"); + + gridCells[i][j]._Gwf->prescribedFire = (int **) Mem_Calloc( 1, + sizeof(int **) * SuperGlobals.max_rgroups, + "_allocate_accumulators(Gwf->prescribedfire"); + + ForEachGroup(rg){ + gridCells[i][j]._Gwf->prescribedFire[rg] = (int *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(int) * SuperGlobals.runModelYears, + "_allocate_accumulators(Gwf->prescribedFire)"); + } + } + } + + if (MortFlags.group) { + gridCells[i][j]._Gestab = (struct stat_st *) + Mem_Calloc( Globals->grpCount, + sizeof(struct stat_st), + "_allocate_accumulators(Gestab)"); + + gridCells[i][j]._Gmort = (struct stat_st *) + Mem_Calloc( Globals->grpCount, + sizeof(struct stat_st), + "_allocate_accumulators(Gmort)"); + ForEachGroup(rg){ + gridCells[i][j]._Gestab[rg].s = (struct accumulators_st *) + Mem_Calloc( 1, sizeof(struct accumulators_st), + "_allocate_accumulators(Gestab[rg].s)"); + gridCells[i][j]._Gmort[rg].s = (struct accumulators_st *) + Mem_Calloc( GrpMaxAge(rg), + sizeof(struct accumulators_st), + "_allocate_accumulators(Gmort[rg].s)"); + } + } + + if (BmassFlags.sppb) { + gridCells[i][j]._Spp = (struct stat_st *) + Mem_Calloc( Globals->sppCount, + sizeof(struct stat_st), + "_allocate_accumulators(Spp)"); + ForEachSpecies(sp){ + gridCells[i][j]._Spp[sp].s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Spp[sp].s)"); + } -/***********************************************************/ -static void _free_individuals(IndivType *head) -{ - //frees the memory allocated in the linked list of individuals pointed to by head - if (head->Next != NULL) - _free_individuals(head->Next); //recursively call itself in order to free the next obj in the list (Mem_Free() will end up getting called on the objects in the list from last to first) - Mem_Free(head); + if (BmassFlags.indv) { + gridCells[i][j]._Indv = (struct stat_st *) + Mem_Calloc( Globals->sppCount, + sizeof(struct stat_st), + "_allocate_accumulators(Indv)"); + ForEachSpecies(sp){ + gridCells[i][j]._Indv[sp].s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Indv[sp].s)"); + } + } + } + if (MortFlags.species) { + gridCells[i][j]._Sestab = (struct stat_st *) + Mem_Calloc( Globals->sppCount, + sizeof(struct stat_st), + "_allocate_accumulators(Sestab)"); + + gridCells[i][j]._Smort = (struct stat_st *) + Mem_Calloc( Globals->sppCount, + sizeof(struct stat_st), + "_allocate_accumulators(Smort)"); + + ForEachSpecies(sp){ + gridCells[i][j]._Sestab[sp].s = (struct accumulators_st *) + Mem_Calloc( 1, sizeof(struct accumulators_st), + "_allocate_accumulators(Sestab[sp].s)"); + gridCells[i][j]._Smort[sp].s = (struct accumulators_st *) + Mem_Calloc( SppMaxAge(sp), + sizeof(struct accumulators_st), + "_allocate_accumulators(Smort[sp].s)"); + } + } + + if (UseSeedDispersal) { + gridCells[i][j]._Sreceived = Mem_Calloc( Globals->sppCount, sizeof(struct stat_st), "_allocate_accumulators(Sreceived)"); + + ForEachSpecies(sp) { + gridCells[i][j]._Sreceived[sp].s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(struct accumulators_st), + "_allocate_accumulators(Sreceived[sp].s)"); + gridCells[i][j]._Sreceived[sp].name = &Species[sp]->name[0]; + } + } + + /* "appoint" names of columns*/ + if (BmassFlags.grpb) { + ForEachGroup(rg) + gridCells[i][j]._Grp[rg].name = &RGroup[rg]->name[0]; + } + if (MortFlags.group) { + ForEachGroup(rg) + gridCells[i][j]._Gmort[rg].name = &RGroup[rg]->name[0]; + } + if (BmassFlags.sppb) { + ForEachSpecies(sp) + gridCells[i][j]._Spp[sp].name = &Species[sp]->name[0]; + } + if (MortFlags.species) { + ForEachSpecies(sp) + gridCells[i][j]._Smort[sp].name = &Species[sp]->name[0]; + } + } /* End for each column */ + } /* End for each row */ + unload_cell(); // Unload the cell to protect the last cell from unintended modification. } -/***********************************************************/ -static void _free_head(IndivType * head) +/* Free all memory allocated to the gridded mode during initialization. */ +void free_grid_memory(void) { - if (head == NULL) - return; //if head == NULL then there is no memory to free, so just return - _free_individuals(head); + //frees all the memory allocated in this file ST_Grid.c (most of it is dynamically allocated in _init_grid_globals() & _load_grid_globals() functions) + int i, j, sd_i; + SppIndex s; + + /* Free memory that we have allocated in ST_grid.c */ + for(i = 0; i < grid_Rows; ++i){ + for(j = 0; j < grid_Cols; ++j){ + /* Use deallocate_Globals from ST_main to deallocate global variables, + and free_all_sxw_memory from sxw to deallocate SXW variables. */ + load_cell(i,j); + deallocate_Globals(TRUE); + free_all_sxw_memory(); + stat_free_mem(); + // If seed dispersal is on we allocated additional memory + if(UseSeedDispersal) { + ForEachSpecies(s) { + for(sd_i = 0; sd_i < grid_Rows; ++sd_i){ + Mem_Free(gridCells[i][j].mySeedDispersal[s].dispersalProb[sd_i]); + } + Mem_Free(gridCells[i][j].mySeedDispersal[s].dispersalProb); + } + } + unload_cell(); + + Mem_Free(gridCells[i][j].mySpeciesInit.shouldBeInitialized); + Mem_Free(gridCells[i][j].mySeedDispersal); + Mem_Free(gridCells[i][j].someKillage); + + Mem_Free(gridCells[i][j].mySoils.depth); + Mem_Free(gridCells[i][j].mySoils.evco); + Mem_Free(gridCells[i][j].mySoils.gravel); + Mem_Free(gridCells[i][j].mySoils.imperm); + Mem_Free(gridCells[i][j].mySoils.matricd); + Mem_Free(gridCells[i][j].mySoils.pclay); + Mem_Free(gridCells[i][j].mySoils.psand); + Mem_Free(gridCells[i][j].mySoils.soiltemp); + Mem_Free(gridCells[i][j].mySoils.trco_forb); + Mem_Free(gridCells[i][j].mySoils.trco_grass); + Mem_Free(gridCells[i][j].mySoils.trco_shrub); + Mem_Free(gridCells[i][j].mySoils.trco_tree); + } + } + + for(i = 0; i < grid_Rows; ++i){ + Mem_Free(gridCells[i]); + } + Mem_Free(gridCells); } -/***********************************************************/ -static IndivType* _copy_individuals(IndivType *head) -{ - //performs a deep copy (not to be confused with a shallow copy) since that's what we want - IndivType *n = _create_empty_indv(); //allocate space for the individual to be copied to +/* Load gridCells[row][col] into the globals variables. + Any call to this function should have an accompanying call to unload_cell(). */ +void load_cell(int row, int col){ + /* RGroup for this cell */ + RGroup = gridCells[row][col].myGroup; - *n = *head; + /*Species for this cell */ + Species = gridCells[row][col].mySpecies; - if (head->Next != NULL) - { - n->Next = _copy_individuals(head->Next); //recursively call itself in order to copy the next obj in the list - n->Next->Prev = n; - } - else - n->Next = NULL; + /* Succulents corresponding to this cell */ + Succulent = &gridCells[row][col].mySucculent; - return n; -} + /* This cell's environment. We expect each cell to + * have slightly different weather each year */ + Env = &gridCells[row][col].myEnvironment; -/***********************************************************/ -static IndivType* _copy_head(IndivType *head) -{ - if (head == NULL) - return NULL; //if head == NULL then there is nothing to copy... - return _copy_individuals(head); -} + /* Cell's plot data */ + Plot = &gridCells[row][col].myPlot; -/**********************************************************/ -/* - static void _copy_species(SpeciesType* to, SpeciesType* from, Bool deep) { - if(deep) { - Mem_Free(to->kills); - Mem_Free(to->seedprod); - _free_head(to->IndvHead); //free_head() frees the memory allocated by the head and the memory allocated by each part of the linked list - } - - *to = *from; - to->est_count = from->est_count; - to->estabs = from->estabs; - to->relsize = from->relsize; - to->extragrowth = from->extragrowth; - to->allow_growth = from->allow_growth; - - if(deep) { - to->kills = Mem_Calloc(from->max_age, sizeof(IntUS), "_load_cell(Species[s]->kills)"); - to->seedprod = Mem_Calloc(from->viable_yrs, sizeof(RealF), "_load_cell(Species[s]->seedprod)"); - - memcpy(to->kills, from->kills, from->max_age * sizeof(IntUS)); - memcpy(to->seedprod, from->seedprod, from->viable_yrs * sizeof(RealF)); - to->IndvHead = _copy_head(from->IndvHead); //copy_head() deep copies the linked list structure (allocating memory when needed)... it will even allocate memory for the head of the list - } - } - */ -/***********************************************************/ -static void _init_grid_globals(void) -{ - //initializes grid variables, allocating the memory necessary for them (this step is only needed to be done once) + /* Global variables corresponding to this cell */ + Globals = &gridCells[row][col].myGlobals; - GrpIndex c; - SppIndex s; - int i; + /* TRUE if this cell is in spinup mode */ + DuringInitialization = gridCells[row][col].DuringInitialization; - grid_Succulent = Mem_Calloc(grid_Cells, sizeof(SucculentType), - "_init_grid_globals()"); - grid_Env = Mem_Calloc(grid_Cells, sizeof(EnvType), "_init_grid_globals()"); - grid_Plot = Mem_Calloc(grid_Cells, sizeof(PlotType), - "_init_grid_globals()"); - grid_Globals = Mem_Calloc(grid_Cells, sizeof(ModelType), - "_init_grid_globals()"); - - ForEachSpecies(s) - if (Species[s]->use_me) - grid_Species[s] = Mem_Calloc(grid_Cells, sizeof(SpeciesType), - "_init_grid_globals()"); - ForEachGroup(c) - if (RGroup[c]->use_me) - grid_RGroup[c] = Mem_Calloc(grid_Cells, sizeof(GroupType), - "_init_grid_globals()"); - - grid_SXW = Mem_Calloc(grid_Cells, sizeof(SXW_t), - "_init_grid_globals()"); - grid_SW_Soilwat = Mem_Calloc(grid_Cells, sizeof(SW_SOILWAT), - "_init_grid_globals()"); - grid_SW_Site = Mem_Calloc(grid_Cells, sizeof(SW_SITE), - "_init_grid_globals()"); - grid_SW_VegProd = Mem_Calloc(grid_Cells, sizeof(SW_VEGPROD), - "_init_grid_globals()"); - if (UseSoils) - { - grid_Soils = Mem_Calloc(grid_Cells, sizeof(Grid_Soil_St), - "_init_grid_globals()"); - for (i = 0; i < grid_Cells; i++) - grid_Soils[i].num_layers = 0; - grid_SXW_ptrs = Mem_Calloc(grid_Cells, sizeof(Grid_SXW_St), - "_init_grid_globals()"); - } + _SomeKillage = gridCells[row][col].someKillage; - if (UseDisturbances) - grid_Disturb = Mem_Calloc(grid_Cells, sizeof(Grid_Disturb_St), - "_init_grid_globals()"); - if (UseSeedDispersal) - { - ForEachSpecies(s) - if (Species[s]->use_me && Species[s]->use_dispersal) - grid_SD[s] = Mem_Calloc(grid_Cells, sizeof(Grid_SD_St), - "_init_grid_globals()"); - - grid_initSpecies = Mem_Calloc(grid_Cells, sizeof(Grid_Init_Species_St), - "_init_grid_globals()"); - for (i = 0; i < grid_Cells; i++) - grid_initSpecies[i].species_seed_avail = Mem_Calloc( - Globals.sppCount, sizeof(int), "_init_grid_globals()"); - } + /* Copy this cell's accumulators into the local accumulators in ST_stats.c */ + stat_Copy_Accumulators(gridCells[row][col]._Dist, gridCells[row][col]._Ppt, gridCells[row][col]._Temp, + gridCells[row][col]._Grp, gridCells[row][col]._Gsize, gridCells[row][col]._Gpr, + gridCells[row][col]._Gmort, gridCells[row][col]._Gestab, gridCells[row][col]._Spp, + gridCells[row][col]._Indv, gridCells[row][col]._Smort, gridCells[row][col]._Sestab, + gridCells[row][col]._Sreceived, gridCells[row][col]._Gwf, gridCells[row][col].stats_init); - //if(sd_Option2a || sd_Option2b) { - soilTypes_Array = Mem_Calloc(grid_Cells, sizeof(int*), - "_init_grid_globals()"); - grid_SoilTypes = Mem_Calloc(grid_Cells, sizeof(int*), - "_init_grid_globals()"); - //} + /* Copy this cell's SXW variables into the local variables in sxw.c */ + copy_sxw_variables(gridCells[row][col].mySXW, gridCells[row][col].mySXWResources, gridCells[row][col].myTranspWindow); - stat_Init_Accumulators(); + // If we have read in the soil information num_layers will be > 0. + // Otherwise we haven't read the file so there is no point wasting time on this. + if(gridCells[row][col].mySoils.num_layers > 0){ + RealD soilRegionsLowerBounds[3] = { 30, 70, 100 }; + set_soillayers(gridCells[row][col].mySoils.num_layers, gridCells[row][col].mySoils.depth, gridCells[row][col].mySoils.matricd, + gridCells[row][col].mySoils.gravel, gridCells[row][col].mySoils.evco, gridCells[row][col].mySoils.trco_grass, + gridCells[row][col].mySoils.trco_shrub, gridCells[row][col].mySoils.trco_tree, gridCells[row][col].mySoils.trco_forb, + gridCells[row][col].mySoils.psand, gridCells[row][col].mySoils.pclay, gridCells[row][col].mySoils.imperm, + gridCells[row][col].mySoils.soiltemp, 3, soilRegionsLowerBounds); + } } -/***********************************************************/ -static void _init_spinup_globals(void) -{ - //initializes spinup variables, allocating the memory necessary for them (this step is only needed to be done once) - - GrpIndex c; - SppIndex s; +/* Nullify all global variables. This function should appear after every call + to load_cell to prevent accidental modification of a grid cell. + Example usage: + for i in rows{ + for j in columns{ + load_cell(i, j) + //additional functions + } + } + unload_cell() */ +void unload_cell(){ + Species = NULL; + RGroup = NULL; + Succulent = NULL; + Env = NULL; + Plot = NULL; + Globals = NULL; + // Nullify the accumulators + stat_Copy_Accumulators(NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,FALSE); + // Nullify sxw + copy_sxw_variables(NULL,NULL,NULL); +} - spinup_Succulent = Mem_Calloc(nSoilTypes, sizeof(SucculentType), - "_init_spinup_globals()"); - spinup_Env = Mem_Calloc(nSoilTypes, sizeof(EnvType), - "_init_spinup_globals()"); - spinup_Plot = Mem_Calloc(nSoilTypes, sizeof(PlotType), - "_init_spinup_globals()"); - spinup_Globals = Mem_Calloc(nSoilTypes, sizeof(ModelType), - "_init_spinup_globals()"); - - ForEachSpecies(s) - if (Species[s]->use_me) - spinup_Species[s] = Mem_Calloc(nSoilTypes, sizeof(SpeciesType), - "_init_spinup_globals()"); - ForEachGroup(c) - if (RGroup[c]->use_me) - spinup_RGroup[c] = Mem_Calloc(nSoilTypes, sizeof(GroupType), - "_init_spinup_globals()"); - - spinup_SXW = Mem_Calloc(nSoilTypes, sizeof(SXW_t), - "_init_spinup_globals()"); - spinup_SW_Soilwat = Mem_Calloc(nSoilTypes, sizeof(SW_SOILWAT), - "_init_spinup_globals()"); - spinup_SW_Site = Mem_Calloc(nSoilTypes, sizeof(SW_SITE), - "_init_spinup_globals()"); - spinup_SW_VegProd = Mem_Calloc(nSoilTypes, sizeof(SW_VEGPROD), - "_init_spinup_globals()"); - if (UseSoils) +/* + * \brief Similar to the getaline function in filefuncs.c, except this one + * checks for carriage return characters and doesn't deal with whitespace. + * It treats '\r', '\n', and '\r\n' all like they are valid line feeds. + */ +static Bool GetALine2(FILE *f, char buf[], int limit) +{ + //only read limit characters + int i = 0, aChar; + aChar = getc(f); + if (aChar == EOF) + return FALSE; + while ((i < (limit - 1)) && aChar != EOF && aChar != '\r' && aChar != '\n') { - spinup_SXW_ptrs = Mem_Calloc(nSoilTypes, sizeof(Grid_SXW_St), - "_init_spinup_globals()"); + buf[i++] = (char) aChar; + aChar = getc(f); } + if (aChar == '\r') //this part handles the '\r\n' case + if (getc(f) != '\n') + fseek(f, -1, SEEK_CUR); //back up one character in the file because we didn't find a new-line character + + buf[i] = '\0'; + return TRUE; } -/***********************************************************/ -static void _load_grid_globals(void) +/* Reads the grid disturbance CSV. This function will override disturbance inputs from non-gridded mode. */ +static void _read_disturbances_in(void) { - //this initializes/allocates memory needed... this step is needed to be done for every iteration + FILE *f; + char buf[1024]; + int i, row, col, cell, num = 0; + GrpIndex rg; - int i, j, k; - GrpIndex c; - SppIndex s; + f = OpenFile(grid_files[GRID_FILE_DISTURBANCES], "r"); - if (UseSoils) - ChDir(grid_directories[0]); //change the directory for _init_soil_layers() + GetALine2(f, buf, 1024); // gets rid of the first line (since it just defines the columns) for (i = 0; i < grid_Cells; i++) { + row = i / grid_Cols; + col = i % grid_Cols; - ForEachSpecies(s) - { //macros defined in ST_defines.h - if (!Species[s]->use_me) - continue; - grid_Species[s][i] = *Species[s]; - - grid_Species[s][i].kills = Mem_Calloc(Species[s]->max_age, - sizeof(IntUS), "_init_grid_globals()"); - grid_Species[s][i].seedprod = Mem_Calloc(Species[s]->viable_yrs, - sizeof(RealF), "_init_grid_globals()"); - - memcpy(grid_Species[s][i].kills, Species[s]->kills, - Species[s]->max_age * sizeof(IntUS)); - memcpy(grid_Species[s][i].seedprod, Species[s]->seedprod, - Species[s]->viable_yrs * sizeof(RealF)); - - grid_Species[s][i].IndvHead = _copy_head(Species[s]->IndvHead); //copy_head() deep copies the structure (allocating memory when needed)... it will even allocate memory for the head of the list - } + load_cell(row, col); + + if (!GetALine2(f, buf, 1024)) + break; - ForEachGroup(c) - { - if (!RGroup[c]->use_me) - continue; - grid_RGroup[c][i] = *RGroup[c]; - grid_RGroup[c][i].kills = Mem_Calloc(RGroup[c]->max_age, - sizeof(IntUS), "_init_grid_globals()"); - - memcpy(grid_RGroup[c][i].kills, RGroup[c]->kills, - RGroup[c]->max_age * sizeof(IntUS)); - if (UseDisturbances) - { - grid_RGroup[c][i].killyr = grid_Disturb[i].kill_yr; - grid_RGroup[c][i].killfreq = grid_Disturb[i].killfrq; - grid_RGroup[c][i].extirp = grid_Disturb[i].extirp; - } + ForEachGroup(rg) { + num = sscanf(buf, "%d,%u,%u,%u,%hu,%hu,%f,%hu,%hu,%hu,%f", &cell, + &Globals->pat.use, &Globals->mound.use, &Globals->burrow.use, &RGroup[rg]->killyr, + &RGroup[rg]->killfreq_startyr, &RGroup[rg]->killfreq, &RGroup[rg]->extirp, + &RGroup[rg]->grazingfrq, &RGroup[rg]->grazingfreq_startyr, &RGroup[rg]->ignition); } - grid_Succulent[i] = Succulent; - grid_Env[i] = Env; - grid_Plot[i] = Plot; - grid_Globals[i] = Globals; - - if (UseDisturbances) - { - grid_Globals[i].pat.use = grid_Disturb[i].choices[0]; - grid_Globals[i].mound.use = grid_Disturb[i].choices[1]; - grid_Globals[i].burrow.use = grid_Disturb[i].choices[2]; - } - if (UseSoils) - _init_soil_layers(i, 0); - - grid_SXW[i] = SXW; - - grid_SXW[i].f_roots = Str_Dup(SXW.f_roots); - grid_SXW[i].f_phen = Str_Dup(SXW.f_phen); - grid_SXW[i].f_bvt = Str_Dup(SXW.f_bvt); - grid_SXW[i].f_prod = Str_Dup(SXW.f_prod); - grid_SXW[i].f_watin = Str_Dup(SXW.f_watin); - - grid_SXW[i].transpTotal = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_init_grid_globals()"); - ForEachVegType(k) { - grid_SXW[i].transpVeg[k] = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_init_grid_globals()"); - } - grid_SXW[i].swc = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealF), - "_init_grid_globals()"); - - memcpy(grid_SXW[i].transpTotal, SXW.transpTotal, - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - ForEachVegType(k) { - memcpy(grid_SXW[i].transpVeg[k], SXW.transpVeg[k], - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - } - memcpy(grid_SXW[i].swc, SXW.swc, - SXW.NPds * SXW.NSoLyrs * sizeof(RealF)); - - grid_SW_Soilwat[i] = SW_Soilwat; - grid_SW_Site[i] = SW_Site; - grid_SW_VegProd[i] = SW_VegProd; - - grid_SW_Site[i].lyr = Mem_Calloc( - SW_Site.n_layers + SW_Site.deepdrain, - sizeof(SW_LAYER_INFO *), "_init_grid_globals()"); - for (j = 0; j < SW_Site.n_layers + SW_Site.deepdrain; j++) - { - grid_SW_Site[i].lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_init_grid_globals()"); - memcpy(grid_SW_Site[i].lyr[j], SW_Site.lyr[j], - sizeof(SW_LAYER_INFO)); - } - } - if (UseSoils) - ChDir(".."); //get back to our previous directory + if (num != 11) + LogError(logfp, LOGFATAL, "Invalid %s file line %d wrong", + grid_files[GRID_FILE_DISTURBANCES], i + 2); + } + if (i != grid_Cells) + LogError(logfp, LOGFATAL, "Invalid %s file wrong number of cells", + grid_files[GRID_FILE_DISTURBANCES]); + unload_cell(); + CloseFile(&f); } -/***********************************************************/ -static void _load_spinup_globals(void) +/* Iterates through s until it find nSeperators worth of seperators + * + * Used to do most of the parsing in the \ref _read_soils_in() function + * + * \param s is a char* array. + * \param separator is the character used as a separator, for example tab or space. + * \param nSeparators is the number of separators to read. + * + * \return index of the character following the last separator. */ +static int _get_value_index(char* s, char seperator, int nSeperators) { - //this initializes/allocates memory needed... this step is needed to be done for every iteration - - int i, j, k; - GrpIndex c; - SppIndex s; - - if (UseSoils) - ChDir(grid_directories[0]); //change the directory for _init_soil_layers() - for (i = 0; i < nSoilTypes; i++) + int i = 0, sep = 0; + while (*s) { - - int cell = soilTypes_Array[i]; //this is the cell number of the first cell representing this soil type - - ForEachSpecies(s) - { //macros defined in ST_defines.h - if (!Species[s]->use_me) - continue; - spinup_Species[s][i] = *Species[s]; - - spinup_Species[s][i].kills = Mem_Calloc(Species[s]->max_age, - sizeof(IntUS), "_init_spinup_globals()"); - spinup_Species[s][i].seedprod = Mem_Calloc(Species[s]->viable_yrs, - sizeof(RealF), "_init_spinup_globals()"); - - memcpy(spinup_Species[s][i].kills, Species[s]->kills, - Species[s]->max_age * sizeof(IntUS)); - memcpy(spinup_Species[s][i].seedprod, Species[s]->seedprod, - Species[s]->viable_yrs * sizeof(RealF)); - - spinup_Species[s][i].IndvHead = _copy_head(Species[s]->IndvHead); //copy_head() deep copies the structure (allocating memory when needed)... it will even allocate memory for the head of the list - } - - ForEachGroup(c) - { - if (!RGroup[c]->use_me) - continue; - spinup_RGroup[c][i] = *RGroup[c]; - spinup_RGroup[c][i].kills = Mem_Calloc(RGroup[c]->max_age, - sizeof(IntUS), "_init_spinup_globals()"); - - memcpy(spinup_RGroup[c][i].kills, RGroup[c]->kills, - RGroup[c]->max_age * sizeof(IntUS)); - if (UseDisturbances) - { - spinup_RGroup[c][i].killyr = grid_Disturb[cell].kill_yr; - spinup_RGroup[c][i].killfreq = grid_Disturb[cell].killfrq; - spinup_RGroup[c][i].extirp = grid_Disturb[cell].extirp; - } - } - - spinup_Succulent[i] = Succulent; - spinup_Env[i] = Env; - spinup_Plot[i] = Plot; - spinup_Globals[i] = Globals; - - if (UseDisturbances) - { - spinup_Globals[i].pat.use = grid_Disturb[cell].choices[0]; - spinup_Globals[i].mound.use = grid_Disturb[cell].choices[1]; - spinup_Globals[i].burrow.use = grid_Disturb[cell].choices[2]; - } - if (UseSoils) //TODO: DM should i be cell value after lookup from soilTypes_Array - _init_soil_layers(i, 1); - - spinup_SXW[i] = SXW; - - spinup_SXW[i].f_roots = Str_Dup(SXW.f_roots); - spinup_SXW[i].f_phen = Str_Dup(SXW.f_phen); - spinup_SXW[i].f_bvt = Str_Dup(SXW.f_bvt); - spinup_SXW[i].f_prod = Str_Dup(SXW.f_prod); - spinup_SXW[i].f_watin = Str_Dup(SXW.f_watin); - - spinup_SXW[i].transpTotal = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_init_spinup_globals()"); - ForEachVegType(k) { - spinup_SXW[i].transpVeg[k] = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_init_grid_globals()"); - } - spinup_SXW[i].swc = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealF), "_init_grid_globals()"); - - memcpy(spinup_SXW[i].transpTotal, SXW.transpTotal, - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - ForEachVegType(k) { - memcpy(spinup_SXW[i].transpVeg[k], SXW.transpVeg[k], - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - } - memcpy(spinup_SXW[i].swc, SXW.swc, - SXW.NPds * SXW.NSoLyrs * sizeof(RealF)); - - spinup_SW_Soilwat[i] = SW_Soilwat; - spinup_SW_Site[i] = SW_Site; - spinup_SW_VegProd[i] = SW_VegProd; - - spinup_SW_Site[i].lyr = Mem_Calloc( - SW_Site.n_layers + SW_Site.deepdrain, - sizeof(SW_LAYER_INFO *), "_init_grid_globals()"); - for (j = 0; j < SW_Site.n_layers + SW_Site.deepdrain; j++) - { - spinup_SW_Site[i].lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_init_grid_globals()"); - memcpy(spinup_SW_Site[i].lyr[j], SW_Site.lyr[j], - sizeof(SW_LAYER_INFO)); - } + i++; + if (*s++ == seperator) //checks if the current char equals the seperator... and then increments the char pointer + if (++sep == nSeperators) //needs ++sep, not sep++ + break; } - if (UseSoils) - ChDir(".."); //get back to our previous directory - + return i; } -/***********************************************************/ -static void _free_grid_globals(void) -{ - //frees memory allocated in _load_grid_globals() function. - int i, j, k; - GrpIndex c; - SppIndex s; - - for (i = 0; i < grid_Cells; i++) - { +/* Read the grid_soils.csv file and assign values to all gridCells.mySoils variables. */ +static void _read_soils_in(void){ + int i, row, col, lineReadReturnValue; + char buf[4096]; - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; - Mem_Free(grid_Species[s][i].kills); - Mem_Free(grid_Species[s][i].seedprod); - _free_head(grid_Species[s][i].IndvHead); + /* tempSoil is allocated the maximum amount of memory that a SoilType could need. + It will serve to read in parameters. */ + SoilType tempSoil; + tempSoil.depth = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.evco = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.gravel = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.imperm = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.matricd = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.pclay = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.psand = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.soiltemp = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.trco_forb = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.trco_grass = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.trco_shrub = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + tempSoil.trco_tree = Mem_Calloc(MAX_LAYERS, sizeof(RealF), "_read_soils_in: tempSoil"); + + FILE* f = OpenFile(grid_files[GRID_FILE_SOILS], "r"); + if(!GetALine(f, buf)){ // Throw out the header line. + LogError(logfp, LOGFATAL, "%s file empty.", grid_files[GRID_FILE_SOILS]); + } + + for(i = 0; i < grid_Cells; ++i){ + row = i / grid_Cols; + col = i % grid_Cols; + load_cell(row, col); + + if(!GetALine(f, buf)){ + LogError(logfp, LOGFATAL, "Too few lines in %s", grid_files[GRID_FILE_SOILS]); } - - ForEachGroup(c) - if (RGroup[c]->use_me) - Mem_Free(grid_RGroup[c][i].kills); - - Mem_Free(grid_SXW[i].f_roots); - Mem_Free(grid_SXW[i].f_phen); - Mem_Free(grid_SXW[i].f_bvt); - Mem_Free(grid_SXW[i].f_prod); - Mem_Free(grid_SXW[i].f_watin); - Mem_Free(grid_SXW[i].transpTotal); - ForEachVegType(k) { - Mem_Free(grid_SXW[i].transpVeg[k]); + lineReadReturnValue = _read_soil_line(buf, &tempSoil, 0); + if (lineReadReturnValue == SOIL_READ_FAILURE){ + LogError(logfp, LOGFATAL, "Error reading %s file.", grid_files[GRID_FILE_SOILS]); + } + /* If _read_soil_line didnt return SUCCESS or FAILURE, + it returned a cell number to copy. */ + else if (lineReadReturnValue != SOIL_READ_SUCCESS){ + if(lineReadReturnValue > i){ + LogError(logfp, LOGFATAL, "%s: Attempted to copy values that have not been read yet.\n" + "\tIf you want to copy a soil make sure you define the layers" + "the FIRST time you use it.", grid_files[GRID_FILE_SOILS]); + } + _copy_soils(&gridCells[lineReadReturnValue / grid_Cols][lineReadReturnValue % grid_Cols].mySoils, &gridCells[row][col].mySoils); } - Mem_Free(grid_SXW[i].swc); - if (UseSoils) - { - Mem_Free(grid_SXW_ptrs[i].roots_max); - Mem_Free(grid_SXW_ptrs[i].rootsXphen); - Mem_Free(grid_SXW_ptrs[i].roots_active); - Mem_Free(grid_SXW_ptrs[i].roots_active_rel); - Mem_Free(grid_SXW_ptrs[i].roots_active_sum); - Mem_Free(grid_SXW_ptrs[i].phen); - Mem_Free(grid_SXW_ptrs[i].prod_bmass); - Mem_Free(grid_SXW_ptrs[i].prod_pctlive); + /* If we get here we have successfully populated the first layer of soil. + Now we must populate the rest. */ + else { + for(int j = 1; j < tempSoil.num_layers; ++j){ + if(!GetALine(f, buf)){ + LogError(logfp, LOGFATAL, "Too few lines in %s", grid_files[GRID_FILE_SOILS]); + } + lineReadReturnValue = _read_soil_line(buf, &tempSoil, j); + if(lineReadReturnValue != SOIL_READ_SUCCESS){ + LogError(logfp, LOGFATAL, "Different behavior is specified between layers %d and %d of" + " cell %d in file %s. (Perhaps you specified a cell to copy in one" + " but not the other?)", j, j+1, i, grid_files[GRID_FILE_SOILS]); + } + } + /* And finally copy the temporary soil into the grid. */ + _copy_soils(&tempSoil, &gridCells[row][col].mySoils); } - - for (j = 0; - j < grid_SW_Site[i].n_layers + grid_SW_Site[i].deepdrain; - j++) - Mem_Free(grid_SW_Site[i].lyr[j]); - Mem_Free(grid_SW_Site[i].lyr); - } -} - -/***********************************************************/ -static void _free_spinup_globals(void) -{ - //frees memory allocated in _load_spinup_globals() function. - int i, j, k; - GrpIndex c; - SppIndex s; - - for (i = 0; i < nSoilTypes; i++) - { + unload_cell(); + CloseFile(&f); - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; - Mem_Free(spinup_Species[s][i].kills); - Mem_Free(spinup_Species[s][i].seedprod); - _free_head(spinup_Species[s][i].IndvHead); - } + Mem_Free(tempSoil.soiltemp); + Mem_Free(tempSoil.trco_forb); + Mem_Free(tempSoil.trco_grass); + Mem_Free(tempSoil.trco_shrub); + Mem_Free(tempSoil.trco_tree); + Mem_Free(tempSoil.depth); + Mem_Free(tempSoil.evco); + Mem_Free(tempSoil.gravel); + Mem_Free(tempSoil.imperm); + Mem_Free(tempSoil.matricd); + Mem_Free(tempSoil.pclay); + Mem_Free(tempSoil.psand); +} - ForEachGroup(c) - if (RGroup[c]->use_me) - Mem_Free(spinup_RGroup[c][i].kills); - - Mem_Free(spinup_SXW[i].f_roots); - Mem_Free(spinup_SXW[i].f_phen); - Mem_Free(spinup_SXW[i].f_bvt); - Mem_Free(spinup_SXW[i].f_prod); - Mem_Free(spinup_SXW[i].f_watin); - Mem_Free(spinup_SXW[i].transpTotal); - ForEachVegType(k) { - Mem_Free(spinup_SXW[i].transpVeg[k]); +/* Reads a line of soil input from buf into destination. + + Param buf: line of soil input. + Param destination: SoilType struct to fill. + Param layer: layer number of destination to fill (0 indexed). + + Return: SOIL_READ_FAILURE if buf is incorrectly formatted. + SOIL_READ_SUCCESS if destination is populated correctly. + Otherwise returns the cell number that destination should copy. */ +static int _read_soil_line(char* buf, SoilType* destination, int layer){ + int entriesRead, cellToCopy, cellNum, layerRead; + entriesRead = sscanf(buf, "%d,,%d,%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%s", + &cellNum, &destination->num_layers, &layerRead, &destination->depth[layer], + &destination->matricd[layer], &destination->gravel[layer], + &destination->evco[layer], &destination->trco_grass[layer], + &destination->trco_shrub[layer], &destination->trco_tree[layer], + &destination->trco_forb[layer], &destination->psand[layer], + &destination->pclay[layer], &destination->imperm[layer], + &destination->soiltemp[layer], destination->rootsFile); + + if(cellNum > grid_Cells || layerRead > destination->num_layers){ + LogError(logfp, LOGFATAL, "%s: cells out of order or too many layers.", grid_files[GRID_FILE_SOILS]); + } + + /* If the user specified a cell to copy we will perform the copy, regardless + of whether or not they also entered parameters. */ + if(entriesRead == 1){ + entriesRead = sscanf(buf, "%d,%d", &cellNum, &cellToCopy); + if(entriesRead == 2){ + return cellToCopy; + } else { + return SOIL_READ_FAILURE; } - Mem_Free(spinup_SXW[i].swc); - if (UseSoils) - { - Mem_Free(spinup_SXW_ptrs[i].roots_max); - Mem_Free(spinup_SXW_ptrs[i].rootsXphen); - Mem_Free(spinup_SXW_ptrs[i].roots_active); - Mem_Free(spinup_SXW_ptrs[i].roots_active_rel); - Mem_Free(spinup_SXW_ptrs[i].roots_active_sum); - Mem_Free(spinup_SXW_ptrs[i].phen); - Mem_Free(spinup_SXW_ptrs[i].prod_bmass); - Mem_Free(spinup_SXW_ptrs[i].prod_pctlive); - } - - for (j = 0; - j < spinup_SW_Site[i].n_layers + spinup_SW_Site[i].deepdrain; - j++) - Mem_Free(spinup_SW_Site[i].lyr[j]); - Mem_Free(spinup_SW_Site[i].lyr); } + if(entriesRead == 16) { + return SOIL_READ_SUCCESS; + } else { + return SOIL_READ_FAILURE; + } } -/***********************************************************/ -static void _free_grid_memory(void) -{ - //frees all the memory allocated in this file ST_Grid.c (most of it is dynamically allocated in _init_grid_globals() & _load_grid_globals() functions) - +/* Copy one SoilType variable to another. + param src: An allocated and assigned SoilType + param dest: An unallocated SoilType + + note: dest will be allocated memory, so do not call this function + if dest is already allocated. */ +void _copy_soils(SoilType* src, SoilType* dest){ int i; - GrpIndex c; - SppIndex s; - - _free_grid_globals(); - if (sd_Option2a || sd_Option2b) - _free_spinup_memory(); - - ForEachSpecies(s) - if (Species[s]->use_me) - Mem_Free(grid_Species[s]); - ForEachGroup(c) - if (RGroup[c]->use_me) - Mem_Free(grid_RGroup[c]); - - Mem_Free(grid_Succulent); - Mem_Free(grid_Env); - Mem_Free(grid_Plot); - Mem_Free(grid_Globals); - Mem_Free(grid_SXW); - Mem_Free(grid_SW_Soilwat); - Mem_Free(grid_SW_Site); - Mem_Free(grid_SW_VegProd); - - if (UseSoils) - { - free_all_sxw_memory(); - Mem_Free(grid_SXW_ptrs); - for (i = 0; i < grid_Cells; i++) - Mem_Free(grid_Soils[i].lyr); - Mem_Free(grid_Soils); - } - if (UseDisturbances) - Mem_Free(grid_Disturb); - if (UseSeedDispersal) - { - ForEachSpecies(s) - if (Species[s]->use_me && Species[s]->use_dispersal) - { - for (i = 0; i < grid_Cells; i++) - { - Mem_Free(grid_SD[s][i].cells); - Mem_Free(grid_SD[s][i].prob); - grid_SD[s][i].size = 0; - } - Mem_Free(grid_SD[s]); - } - - for (i = 0; i < grid_Cells; i++) - Mem_Free(grid_initSpecies[i].species_seed_avail); - Mem_Free(grid_initSpecies); - } - - stat_Free_Accumulators(); //free our memory we allocated for all the accumulators now that they're unnecessary to have - - for (i = 0; i < N_GRID_DIRECTORIES; i++) //frees the strings allocated in _init_grid_files() - Mem_Free(grid_directories[i]); - for (i = 0; i < N_GRID_FILES; i++) - Mem_Free(grid_files[i]); - - // freeing random memory that other parts of steppe/soilwat allocate... this isn't quite everything but it's a good start - parm_free_memory(); //frees memory allocated in ST_params.c - - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; - _free_head(Species[s]->IndvHead); - Mem_Free(Species[s]->kills); - Mem_Free(Species[s]->seedprod); + dest->num_layers = src->num_layers; + dest->gravel = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: gravel"); + dest->depth = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: depth"); + dest->matricd = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: matricd"); + dest->evco = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: evco"); + dest->trco_grass = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: trco_grass"); + dest->trco_shrub = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: trco_shrub"); + dest->trco_tree = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: trco_tree"); + dest->trco_forb = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: trco_forb"); + dest->psand = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: psand"); + dest->pclay = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: pclay"); + dest->imperm = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: imperm"); + dest->soiltemp = Mem_Calloc(src->num_layers, sizeof(RealF), "_copy_Soils: soiltemp"); + + for(i = 0; i < src->num_layers; ++i){ + dest->gravel[i] = src->gravel[i]; + dest->evco[i] = src->evco[i]; + dest->depth[i] = src->depth[i]; + dest->matricd[i] = src->matricd[i]; + dest->trco_shrub[i] = src->trco_shrub[i]; + dest->trco_grass[i] = src->trco_grass[i]; + dest->trco_forb[i] = src->trco_forb[i]; + dest->trco_tree[i] = src->trco_tree[i]; + dest->psand[i] = src->psand[i]; + dest->pclay[i] = src->pclay[i]; + dest->imperm[i] = src->imperm[i]; + dest->soiltemp[i] = src->soiltemp[i]; } - - ForEachGroup(c) - if (RGroup[c]->use_me) - Mem_Free(RGroup[c]->kills); - - for (i = 0; i < SW_Site.n_layers + SW_Site.deepdrain; i++) - Mem_Free(SW_Site.lyr[i]); - Mem_Free(SW_Site.lyr); - } -/***********************************************************/ -static void _free_spinup_memory(void) +/* Read the species initialization CSV. This function only needs to be called if the user requests initialization.*/ +static void _read_init_species(void) { - // frees spinup memory - - GrpIndex c; - SppIndex s; - - _free_spinup_globals(); - - ForEachSpecies(s) - if (Species[s]->use_me) - Mem_Free(spinup_Species[s]); - ForEachGroup(c) - if (RGroup[c]->use_me) - Mem_Free(spinup_RGroup[c]); - - Mem_Free(spinup_Succulent); - Mem_Free(spinup_Env); - Mem_Free(spinup_Plot); - Mem_Free(spinup_Globals); + FILE *f; + int i, j, num, cell, do_copy, copy_cell, useInitialization, seeds_Avail, + row, col, copy_cell_row, copy_cell_col; + Bool isAnyCellOnForSpinup = FALSE; + char buf[4096]; - Mem_Free(spinup_SXW); - Mem_Free(spinup_SW_Soilwat); - Mem_Free(spinup_SW_Site); - Mem_Free(spinup_SW_VegProd); + //open the file/do the reading + f = OpenFile(grid_files[GRID_FILE_INIT_SPECIES], "r"); - if (UseSoils) + GetALine2(f, buf, 4096); // gets rid of the first line (since it just defines the columns)... it's only there for user readability + for (i = 0; i < grid_Cells; i++) { - Mem_Free(spinup_SXW_ptrs); - } - - //if(sd_Option2a || sd_Option2b) { - Mem_Free(soilTypes_Array); - Mem_Free(grid_SoilTypes); - //} -} + useInitialization = FALSE; + row = i / grid_Cols; + col = i % grid_Cols; -/***********************************************************/ -static void _load_cell(int row, int col, int year, Bool useAccumulators) -{ - // loads the specified cell into the global variables + load_cell(row, col); - int cell = col + ((row - 1) * grid_Cols) - 1; // converts the row/col into an array index - int j, k; - GrpIndex c; - SppIndex s; - //fprintf(stderr, " loading cell: %d; ", cell); - if (useAccumulators) - stat_Load_Accumulators(cell, year); + if (!GetALine2(f, buf, 4096)) + break; - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; + num = sscanf(buf, "%d,%d,%d", &cell, &do_copy, ©_cell); - Mem_Free(Species[s]->kills); - Mem_Free(Species[s]->seedprod); - _free_head(Species[s]->IndvHead); //free_head() frees the memory allocated by the head and the memory allocated by each part of the linked list + copy_cell_row = copy_cell / grid_Cols; + copy_cell_col = copy_cell % grid_Cols; - *Species[s] = grid_Species[s][cell]; + if (num != 3) + LogError(logfp, LOGFATAL, "Invalid %s file", grid_files[GRID_FILE_INIT_SPECIES]); - Species[s]->kills = Mem_Calloc(grid_Species[s][cell].max_age, - sizeof(IntUS), "_load_cell(Species[s]->kills)"); - Species[s]->seedprod = Mem_Calloc(grid_Species[s][cell].viable_yrs, - sizeof(RealF), "_load_cell(Species[s]->seedprod)"); + int stringIndex = _get_value_index(buf, ',', 3); //gets us the index of the string that is right after what we just parsed in - memcpy(Species[s]->kills, grid_Species[s][cell].kills, - grid_Species[s][cell].max_age * sizeof(IntUS)); - memcpy(Species[s]->seedprod, grid_Species[s][cell].seedprod, - grid_Species[s][cell].viable_yrs * sizeof(RealF)); - Species[s]->IndvHead = _copy_head(grid_Species[s][cell].IndvHead); //copy_head() deep copies the linked list structure (allocating memory when needed)... it will even allocate memory for the head of the list + if (do_copy == 1 && copy_cell > -1 && copy_cell < grid_Cells + && cell != 0 && copy_cell < cell) + { //copy this cells values from a previous cell's + for (j = 0; j < Globals->sppCount; j++) + gridCells[row][col].mySpeciesInit.shouldBeInitialized[j] = + gridCells[copy_cell_row][copy_cell_col].mySpeciesInit.shouldBeInitialized[j]; + gridCells[row][col].mySpeciesInit.useInitialization = + gridCells[copy_cell_row][copy_cell_col].mySpeciesInit.useInitialization; + continue; + } + else if (do_copy == 1) + LogError(logfp, LOGFATAL, + "Invalid %s file line %d invalid copy_cell attempt", + grid_files[GRID_FILE_INIT_SPECIES], i + 2); - } + //going through each species + SppIndex s; + ForEachSpecies(s) + { + num = sscanf(&buf[stringIndex], "%d,", &seeds_Avail); + if (num != 1){ + LogError(logfp, LOGFATAL, "Invalid %s file line %d invalid species input", + grid_files[GRID_FILE_INIT_SPECIES], i + 2); + } - ForEachGroup(c) - { - if (!RGroup[c]->use_me) - continue; - Mem_Free(RGroup[c]->kills); //kills is the only pointer in the resourcegroup_st struct (which is what RGroup is defined as)... we need to free it then reallocate it then memcpy it to get the deep copy we want + if(seeds_Avail){ + useInitialization = TRUE; + isAnyCellOnForSpinup = TRUE; + } - *RGroup[c] = grid_RGroup[c][cell]; //does a shallow copy, we have to do the freeing/malloc/memcpy to deep copy (ie copy the values in the pointers instead of the addresses) the pointers. A shallow copy will copy over the values for every non-pointer (C itself does not inherently know how to deep copy, so we must code this behaviour). + gridCells[row][col].mySpeciesInit.shouldBeInitialized[s] = seeds_Avail; + stringIndex += _get_value_index(&buf[stringIndex], ',', 1); + } - RGroup[c]->kills = Mem_Calloc(grid_RGroup[c][cell].max_age, - sizeof(IntUS), "_load_cell(RGroup[c]->kills"); - memcpy(RGroup[c]->kills, grid_RGroup[c][cell].kills, - grid_RGroup[c][cell].max_age * sizeof(IntUS)); + gridCells[row][col].mySpeciesInit.useInitialization = useInitialization; } - Succulent = grid_Succulent[cell]; - Env = grid_Env[cell]; - Plot = grid_Plot[cell]; - Globals = grid_Globals[cell]; - - Mem_Free(SXW.f_roots); - Mem_Free(SXW.f_phen); - Mem_Free(SXW.f_bvt); - Mem_Free(SXW.f_prod); - Mem_Free(SXW.f_watin); - Mem_Free(SXW.transpTotal); - ForEachVegType(k) { - Mem_Free(SXW.transpVeg[k]); - } + if (i != grid_Cells) + LogError(logfp, LOGFATAL, "Invalid %s file, not enough cells", + grid_files[GRID_FILE_INIT_SPECIES]); - if (SXW.swc != NULL) - Mem_Free(SXW.swc); - for (j = 0; j < SW_Site.n_layers + SW_Site.deepdrain; j++) - Mem_Free(SW_Site.lyr[j]); - Mem_Free(SW_Site.lyr); - - SXW = grid_SXW[cell]; - SW_Site = grid_SW_Site[cell]; - SW_Soilwat = grid_SW_Soilwat[cell]; - SW_VegProd = grid_SW_VegProd[cell]; - - SXW.transpTotal = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealD), - "_load_cell(SXW.transp)"); - ForEachVegType(k) { - SXW.transpVeg[k] = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealD), - "_load_cell(SXW.transp)"); - } - SXW.swc = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealF), - "_load_cell(SXW.swc)"); - - SXW.f_roots = Str_Dup(grid_SXW[cell].f_roots); - SXW.f_phen = Str_Dup(grid_SXW[cell].f_phen); - SXW.f_bvt = Str_Dup(grid_SXW[cell].f_bvt); - SXW.f_prod = Str_Dup(grid_SXW[cell].f_prod); - SXW.f_watin = Str_Dup(grid_SXW[cell].f_watin); - memcpy(SXW.transpTotal, grid_SXW[cell].transpTotal, - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - ForEachVegType(k) { - memcpy(SXW.transpVeg[k], grid_SXW[cell].transpVeg[k], - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - } - memcpy(SXW.swc, grid_SXW[cell].swc, - SXW.NPds * SXW.NSoLyrs * sizeof(RealF)); - - SW_Site.lyr = Mem_Calloc( - grid_SW_Site[cell].n_layers + grid_SW_Site[cell].deepdrain, - sizeof(SW_LAYER_INFO *), "_load_cell(SW_Site.lyr)"); - for (j = 0; - j < grid_SW_Site[cell].n_layers + grid_SW_Site[cell].deepdrain; - j++) - { - SW_Site.lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_load_cell(SW_Site.lyr[j])"); - memcpy(SW_Site.lyr[j], grid_SW_Site[cell].lyr[j], - sizeof(SW_LAYER_INFO)); + if(!isAnyCellOnForSpinup){ + LogError(logfp, LOGWARN, "Initialization is on, but no species are turned on for initialization inside %s.", + grid_files[GRID_FILE_INIT_SPECIES]); } - if (UseSoils) - load_sxw_memory(grid_SXW_ptrs[cell].roots_max, - grid_SXW_ptrs[cell].rootsXphen, - grid_SXW_ptrs[cell].roots_active, - grid_SXW_ptrs[cell].roots_active_rel, - grid_SXW_ptrs[cell].roots_active_sum, - grid_SXW_ptrs[cell].phen, grid_SXW_ptrs[cell].prod_bmass, - grid_SXW_ptrs[cell].prod_pctlive); + unload_cell(); + CloseFile(&f); } -/***********************************************************/ -static void _load_spinup_cell(int cell) +/* Read the maxrgroupspecies file. */ +static void _read_maxrgroupspecies(void) { - // loads the specified cell into the global variables (from the spinup) - - int j, k; - GrpIndex c; - SppIndex s; - - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; - - Mem_Free(Species[s]->kills); - Mem_Free(Species[s]->seedprod); - _free_head(Species[s]->IndvHead); //free_head() frees the memory allocated by the head and the memory allocated by each part of the linked list - - *Species[s] = spinup_Species[s][cell]; - - Species[s]->kills = Mem_Calloc(spinup_Species[s][cell].max_age, - sizeof(IntUS), "_load_spinup_cell(Species[s]->kills)"); - Species[s]->seedprod = Mem_Calloc(spinup_Species[s][cell].viable_yrs, - sizeof(RealF), "_load_spinup_cell(Species[s]->seedprod)"); - - memcpy(Species[s]->kills, spinup_Species[s][cell].kills, - spinup_Species[s][cell].max_age * sizeof(IntUS)); - memcpy(Species[s]->seedprod, spinup_Species[s][cell].seedprod, - spinup_Species[s][cell].viable_yrs * sizeof(RealF)); - Species[s]->IndvHead = _copy_head(spinup_Species[s][cell].IndvHead); //copy_head() deep copies the linked list structure (allocating memory when needed)... it will even allocate memory for the head of the list - - } - - ForEachGroup(c) - { - if (!RGroup[c]->use_me) - continue; - Mem_Free(RGroup[c]->kills); //kills is the only pointer in the resourcegroup_st struct (which is what RGroup is defined as)... we need to free it then reallocate it then memcpy it to get the deep copy we want - - *RGroup[c] = spinup_RGroup[c][cell]; //does a shallow copy, we have to do the freeing/malloc/memcpy to deep copy (ie copy the values in the pointers instead of the addresses) the pointers. A shallow copy will copy over the values for every non-pointer (C itself does not inherently know how to deep copy, so we must code this behaviour). - - RGroup[c]->kills = Mem_Calloc(spinup_RGroup[c][cell].max_age, - sizeof(IntUS), "_load_spinup_cell(RGroup[c]->kills"); - memcpy(RGroup[c]->kills, spinup_RGroup[c][cell].kills, - spinup_RGroup[c][cell].max_age * sizeof(IntUS)); - } - - Succulent = spinup_Succulent[cell]; - Env = spinup_Env[cell]; - Plot = spinup_Plot[cell]; - Globals = spinup_Globals[cell]; - - Mem_Free(SXW.f_roots); - Mem_Free(SXW.f_phen); - Mem_Free(SXW.f_bvt); - Mem_Free(SXW.f_prod); - Mem_Free(SXW.f_watin); - Mem_Free(SXW.transpTotal); - ForEachVegType(k) { - Mem_Free(SXW.transpVeg[k]); - } - if (SXW.swc != NULL) - Mem_Free(SXW.swc); - for (j = 0; j < SW_Site.n_layers + SW_Site.deepdrain; j++) - Mem_Free(SW_Site.lyr[j]); - Mem_Free(SW_Site.lyr); - - SXW = spinup_SXW[cell]; - SW_Site = spinup_SW_Site[cell]; - SW_Soilwat = spinup_SW_Soilwat[cell]; - SW_VegProd = spinup_SW_VegProd[cell]; - - SXW.transpTotal = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealD), - "_load_spinup_cell(SXW.transpTotal)"); - ForEachVegType(k) { - SXW.transpVeg[k] = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealD), - "_load_spinup_cell(SXW.transpVeg)"); - } - SXW.swc = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealF), - "_load_spinup_cell(SXW.swc)"); - - SXW.f_roots = Str_Dup(spinup_SXW[cell].f_roots); - SXW.f_phen = Str_Dup(spinup_SXW[cell].f_phen); - SXW.f_bvt = Str_Dup(spinup_SXW[cell].f_bvt); - SXW.f_prod = Str_Dup(spinup_SXW[cell].f_prod); - SXW.f_watin = Str_Dup(spinup_SXW[cell].f_watin); - memcpy(SXW.transpTotal, spinup_SXW[cell].transpTotal, - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - ForEachVegType(k) { - memcpy(SXW.transpVeg[k], spinup_SXW[cell].transpVeg[k], - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - } - memcpy(SXW.swc, spinup_SXW[cell].swc, - SXW.NPds * SXW.NSoLyrs * sizeof(RealF)); - - SW_Site.lyr = Mem_Calloc( - spinup_SW_Site[cell].n_layers + spinup_SW_Site[cell].deepdrain, - sizeof(SW_LAYER_INFO *), "_load_spinup_cell(SW_Site.lyr)"); - for (j = 0; - j < spinup_SW_Site[cell].n_layers - + spinup_SW_Site[cell].deepdrain; j++) - { - SW_Site.lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_load_spinup_cell(SW_Site.lyr[j])"); - memcpy(SW_Site.lyr[j], spinup_SW_Site[cell].lyr[j], - sizeof(SW_LAYER_INFO)); - } - - if (UseSoils) - load_sxw_memory(spinup_SXW_ptrs[cell].roots_max, - spinup_SXW_ptrs[cell].rootsXphen, - spinup_SXW_ptrs[cell].roots_active, - spinup_SXW_ptrs[cell].roots_active_rel, - spinup_SXW_ptrs[cell].roots_active_sum, - spinup_SXW_ptrs[cell].phen, - spinup_SXW_ptrs[cell].prod_bmass, - spinup_SXW_ptrs[cell].prod_pctlive); + ChDir(grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS]); + parm_SetName(grid_files[GRID_FILE_MAXRGROUPSPECIES], F_MaxRGroupSpecies); + maxrgroupspecies_init(); + ChDir(".."); } -/***********************************************************/ -static void _save_cell(int row, int col, int year, Bool useAccumulators) +/* Read the non-gridded mode files.in file. */ +static void _read_files(void) { - // saves the specified cell into the grid variables + ChDir(grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS]); + files_init(); + ChDir(".."); +} - int cell = col + ((row - 1) * grid_Cols) - 1; // converts the row/col into an array index - int j, k; - GrpIndex c; - SppIndex s; - //fprintf(stderr, "saving cell: %d\n", cell); +/* Reads the grid setup file and allocates gridCells.*/ +static void _read_grid_setup(void) +{ + FILE *f; + char buf[1024], initializationType[1024]; + int i, j; - if (useAccumulators) - stat_Save_Accumulators(cell, year); + f = OpenFile(grid_files[GRID_FILE_SETUP], "r"); - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; + GetALine(f, buf); + i = sscanf(buf, "%d %d", &grid_Rows, &grid_Cols); + if (i != 2) + LogError(logfp, LOGFATAL, + "Invalid grid setup file (rows/cols line wrong)"); - Mem_Free(grid_Species[s][cell].kills); - Mem_Free(grid_Species[s][cell].seedprod); - _free_head(grid_Species[s][cell].IndvHead); + grid_Cells = grid_Cols * grid_Rows; - grid_Species[s][cell] = *Species[s]; + if (grid_Cells > MAX_CELLS) + LogError(logfp, LOGFATAL, + "Number of cells in grid exceeds MAX_CELLS defined in ST_defines.h"); - grid_Species[s][cell].kills = Mem_Calloc(Species[s]->max_age, - sizeof(IntUS), "_save_cell(grid_Species[cell][s].kills)"); - grid_Species[s][cell].seedprod = Mem_Calloc(Species[s]->viable_yrs, - sizeof(RealF), "_save_cell(grid_Species[cell][s].seedprod)"); + /* Allocate the 2d array of cells now that we know how many we need */ + _allocate_gridCells(grid_Rows, grid_Cols); - memcpy(grid_Species[s][cell].kills, Species[s]->kills, - Species[s]->max_age * sizeof(IntUS)); - memcpy(grid_Species[s][cell].seedprod, Species[s]->seedprod, - Species[s]->viable_yrs * sizeof(RealF)); - grid_Species[s][cell].IndvHead = _copy_head(Species[s]->IndvHead); - } + GetALine(f, buf); + i = sscanf(buf, "%u", &UseDisturbances); + if (i != 1) + LogError(logfp, LOGFATAL, + "Invalid grid setup file (disturbances line wrong)"); - ForEachGroup(c) - { - if (!RGroup[c]->use_me) - continue; - Mem_Free(grid_RGroup[c][cell].kills); //kills is the only pointer in the resourcegroup_st struct (which is what RGroup is defined as) + GetALine(f, buf); + i = sscanf(buf, "%u", &UseSoils); + if (i != 1) + LogError(logfp, LOGFATAL, "Invalid grid setup file (soils line wrong)"); - grid_RGroup[c][cell] = *RGroup[c]; //does a shallow copy, we have to do the freeing/malloc/memcpy to deep copy (i.e. copy the values in the pointers instead of the addresses) the pointers + GetALine(f, buf); + i = sscanf(buf, "%d", &j); + if (i != 1) + LogError(logfp, LOGFATAL, + "Invalid grid setup file (seed dispersal line wrong)"); + UseSeedDispersal = itob(j); - grid_RGroup[c][cell].kills = Mem_Calloc(RGroup[c]->max_age, - sizeof(IntUS), "_save_cell(grid_RGroup[cell][c].kills)"); - memcpy(grid_RGroup[c][cell].kills, RGroup[c]->kills, - RGroup[c]->max_age * sizeof(IntUS)); + // TODO: Remove this block once seed dispersal works. + if(UseSeedDispersal){ + printf("\nSeed dispersal during the simulation is not yet functional.\n" + "Check out GitHub for updates on this feature.\n"); + UseSeedDispersal = FALSE; } - grid_Succulent[cell] = Succulent; - grid_Env[cell] = Env; - grid_Plot[cell] = Plot; - grid_Globals[cell] = Globals; - - Mem_Free(grid_SXW[cell].f_roots); - Mem_Free(grid_SXW[cell].f_phen); - Mem_Free(grid_SXW[cell].f_bvt); - Mem_Free(grid_SXW[cell].f_prod); - Mem_Free(grid_SXW[cell].f_watin); - Mem_Free(grid_SXW[cell].transpTotal); - ForEachVegType(k) { - Mem_Free(grid_SXW[cell].transpVeg[k]); - } - Mem_Free(grid_SXW[cell].swc); - for (j = 0; - j < grid_SW_Site[cell].n_layers + grid_SW_Site[cell].deepdrain; - j++) - Mem_Free(grid_SW_Site[cell].lyr[j]); - Mem_Free(grid_SW_Site[cell].lyr); - - grid_SXW[cell] = SXW; - grid_SW_Site[cell] = SW_Site; - grid_SW_Soilwat[cell] = SW_Soilwat; - grid_SW_VegProd[cell] = SW_VegProd; - - grid_SXW[cell].transpTotal = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_save_cell(grid_SXW[cell].transp)"); - ForEachVegType(k) { - grid_SXW[cell].transpVeg[k] = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_save_cell(grid_SXW[cell].transp)"); + GetALine(f, buf); + i = sscanf(buf, "%s", initializationType); + if(i < 1){ + LogError(logfp, LOGFATAL, "Invalid grid setup file (Initialization line wrong)"); } - grid_SXW[cell].swc = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealF), - "_save_cell(grid_SXW[cell].swc)"); - - grid_SXW[cell].f_roots = Str_Dup(SXW.f_roots); - grid_SXW[cell].f_phen = Str_Dup(SXW.f_phen); - grid_SXW[cell].f_bvt = Str_Dup(SXW.f_bvt); - grid_SXW[cell].f_prod = Str_Dup(SXW.f_prod); - grid_SXW[cell].f_watin = Str_Dup(SXW.f_watin); - memcpy(grid_SXW[cell].transpTotal, SXW.transpTotal, - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - ForEachVegType(k) { - memcpy(grid_SXW[cell].transpVeg[k], SXW.transpVeg[k], - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); + if(!strncmp(initializationType, "spinup", 6)){ + initializationMethod = INIT_WITH_SPINUP; + } else if(!strncmp(initializationType, "seeds", 5)){ + initializationMethod = INIT_WITH_SEEDS; + } else if(!strncmp(initializationType, "none", 4)){ + initializationMethod = INIT_WITH_NOTHING; + } else { + LogError(logfp, LOGFATAL, + "Invalid grid setup file (Initialization line wrong. Valid options are \"spinup\", \"seeds\", or \"none\")"); } - memcpy(grid_SXW[cell].swc, SXW.swc, - SXW.NPds * SXW.NSoLyrs * sizeof(RealF)); - grid_SW_Site[cell].lyr = Mem_Calloc( - SW_Site.n_layers + SW_Site.deepdrain, sizeof(SW_LAYER_INFO *), - "_save_cell(grid_SW_Site[cell].lyr[j])"); - for (j = 0; j < SW_Site.n_layers + SW_Site.deepdrain; j++) - { - grid_SW_Site[cell].lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_save_cell(grid_SW_Site[cell].lyr[j])"); - memcpy(grid_SW_Site[cell].lyr[j], SW_Site.lyr[j], - sizeof(SW_LAYER_INFO)); + GetALine(f, buf); + i = sscanf(buf, "%hd", &SuperGlobals.runInitializationYears); + if(i < 1){ + LogError(logfp, LOGFATAL, "Invalid grid setup file (Initialization years line wrong)"); } - if (UseSoils) - save_sxw_memory(grid_SXW_ptrs[cell].roots_max, - grid_SXW_ptrs[cell].rootsXphen, - grid_SXW_ptrs[cell].roots_active, - grid_SXW_ptrs[cell].roots_active_rel, - grid_SXW_ptrs[cell].roots_active_sum, - grid_SXW_ptrs[cell].phen, grid_SXW_ptrs[cell].prod_bmass, - grid_SXW_ptrs[cell].prod_pctlive); -} - -/***********************************************************/ -static void _save_spinup_cell(int cell) -{ - // saves the specified cell into the grid variables (from the spinup) - - int j, k; - GrpIndex c; - SppIndex s; - - ForEachSpecies(s) - { - if (!Species[s]->use_me) - continue; - - Mem_Free(spinup_Species[s][cell].kills); - Mem_Free(spinup_Species[s][cell].seedprod); - _free_head(spinup_Species[s][cell].IndvHead); - - spinup_Species[s][cell] = *Species[s]; - - spinup_Species[s][cell].kills = Mem_Calloc(Species[s]->max_age, - sizeof(IntUS), "_save_cell(grid_Species[cell][s].kills)"); - spinup_Species[s][cell].seedprod = Mem_Calloc(Species[s]->viable_yrs, - sizeof(RealF), "_save_cell(grid_Species[cell][s].seedprod)"); - - memcpy(spinup_Species[s][cell].kills, Species[s]->kills, - Species[s]->max_age * sizeof(IntUS)); - memcpy(spinup_Species[s][cell].seedprod, Species[s]->seedprod, - Species[s]->viable_yrs * sizeof(RealF)); - spinup_Species[s][cell].IndvHead = _copy_head(Species[s]->IndvHead); + GetALine(f, buf); + i = sscanf(buf, "%u", &writeIndividualFiles); + if(i < 1){ + LogError(logfp, LOGFATAL, "Invalid grid setup file (Individual output line wrong)"); } - ForEachGroup(c) - { - if (!RGroup[c]->use_me) - continue; - Mem_Free(spinup_RGroup[c][cell].kills); //kills is the only pointer in the resourcegroup_st struct (which is what RGroup is defined as) - - spinup_RGroup[c][cell] = *RGroup[c]; //does a shallow copy, we have to do the freeing/malloc/memcpy to deep copy (i.e. copy the values in the pointers instead of the addresses) the pointers - - spinup_RGroup[c][cell].kills = Mem_Calloc(RGroup[c]->max_age, - sizeof(IntUS), "_save_cell(grid_RGroup[cell][c].kills)"); - memcpy(spinup_RGroup[c][cell].kills, RGroup[c]->kills, - RGroup[c]->max_age * sizeof(IntUS)); - } + GetALine(f, buf); + if (sscanf(buf, "%u", &sd_DoOutput) != 1) + LogError(logfp, LOGFATAL, + "Invalid %s file: seed dispersal output line\n", grid_files[GRID_FILE_SETUP]); - spinup_Succulent[cell] = Succulent; - spinup_Env[cell] = Env; - spinup_Plot[cell] = Plot; - spinup_Globals[cell] = Globals; - - Mem_Free(spinup_SXW[cell].f_roots); - Mem_Free(spinup_SXW[cell].f_phen); - Mem_Free(spinup_SXW[cell].f_bvt); - Mem_Free(spinup_SXW[cell].f_prod); - Mem_Free(spinup_SXW[cell].f_watin); - Mem_Free(spinup_SXW[cell].transpTotal); - ForEachVegType(k) { - Mem_Free(spinup_SXW[cell].transpVeg[k]); - } - Mem_Free(spinup_SXW[cell].swc); - for (j = 0; - j - < spinup_SW_Site[cell].n_layers - + spinup_SW_Site[cell].deepdrain; j++) - Mem_Free(spinup_SW_Site[cell].lyr[j]); - Mem_Free(spinup_SW_Site[cell].lyr); - - spinup_SXW[cell] = SXW; - spinup_SW_Site[cell] = SW_Site; - spinup_SW_Soilwat[cell] = SW_Soilwat; - spinup_SW_VegProd[cell] = SW_VegProd; - - spinup_SXW[cell].transpTotal = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_save_cell(grid_SXW[cell].transp)"); - ForEachVegType(k) { - spinup_SXW[cell].transpVeg[k] = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, - sizeof(RealD), "_save_cell(grid_SXW[cell].transp)"); - } - spinup_SXW[cell].swc = Mem_Calloc(SXW.NPds * SXW.NSoLyrs, sizeof(RealF), - "_save_cell(grid_SXW[cell].swc)"); - - spinup_SXW[cell].f_roots = Str_Dup(SXW.f_roots); - spinup_SXW[cell].f_phen = Str_Dup(SXW.f_phen); - spinup_SXW[cell].f_bvt = Str_Dup(SXW.f_bvt); - spinup_SXW[cell].f_prod = Str_Dup(SXW.f_prod); - spinup_SXW[cell].f_watin = Str_Dup(SXW.f_watin); - memcpy(spinup_SXW[cell].transpTotal, SXW.transpTotal, - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - ForEachVegType(k) { - memcpy(spinup_SXW[cell].transpVeg[k], SXW.transpVeg[k], - SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); - } - memcpy(spinup_SXW[cell].swc, SXW.swc, - SXW.NPds * SXW.NSoLyrs * sizeof(RealF)); + GetALine(f, buf); + if (sscanf(buf, "%c", &sd_Sep) != 1) + LogError(logfp, LOGFATAL, + "Invalid %s file: seed dispersal seperator line\n", + grid_files[GRID_FILE_SETUP]); - spinup_SW_Site[cell].lyr = Mem_Calloc( - SW_Site.n_layers + SW_Site.deepdrain, sizeof(SW_LAYER_INFO *), - "_save_cell(grid_SW_Site[cell].lyr[j])"); - for (j = 0; j < SW_Site.n_layers + SW_Site.deepdrain; j++) - { - spinup_SW_Site[cell].lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_save_cell(grid_SW_Site[cell].lyr[j])"); - memcpy(spinup_SW_Site[cell].lyr[j], SW_Site.lyr[j], - sizeof(SW_LAYER_INFO)); - } + if (sd_Sep == 't') //dealing with tab and space special cases... + sd_Sep = '\t'; + else if (sd_Sep == 's') + sd_Sep = ' '; - if (UseSoils) - save_sxw_memory(spinup_SXW_ptrs[cell].roots_max, - spinup_SXW_ptrs[cell].rootsXphen, - spinup_SXW_ptrs[cell].roots_active, - spinup_SXW_ptrs[cell].roots_active_rel, - spinup_SXW_ptrs[cell].roots_active_sum, - spinup_SXW_ptrs[cell].phen, - spinup_SXW_ptrs[cell].prod_bmass, - spinup_SXW_ptrs[cell].prod_pctlive); + CloseFile(&f); } -/**************************************************************/ -static Bool GetALine2(FILE *f, char buf[], int limit) -{ - //this is similar to the getaline function in filefuncs.c, except this one checks for carriage return characters and doesn't deal with whitespace/... (since excel writes them into .csv files for some aggravating reason)... this one is probably less efficient overall though. - //this is treating '\r', '\n', and '\r\n' all like they are valid line feed characters... in reality '\r' by itself should never be, but it's not like I can stop excel from outputting .csv files however the heck it feels like... - //only read limit characters - int i = 0, aChar; - aChar = getc(f); - if (aChar == EOF) - return FALSE; - while ((i < (limit - 1)) && aChar != EOF && aChar != '\r' && aChar != '\n') - { - buf[i++] = (char) aChar; - aChar = getc(f); - } - if (aChar == '\r') //this part handles the '\r\n' case - if (getc(f) != '\n') - fseek(f, -1, SEEK_CUR); //back up one character in the file because we didn't find a new-line character +/* Output a master .csv file containing the averages across all cells. */ +void _Output_AllCellAvgBmass(const char * filename){ + int i, j, year, nobs = 0; //for iterating + GrpIndex rg; //for iterating + SppIndex sp; //for iterating + + /* One accumulator for every accumulator in ST_stats.c */ + float ppt, pptstd, pptsos, temp, tempstd, tempsos, dist, wildfire, grp[SuperGlobals.max_rgroups], grpstd[SuperGlobals.max_rgroups], + grpsos[SuperGlobals.max_rgroups], gsize[SuperGlobals.max_rgroups], gpr[SuperGlobals.max_rgroups], + gprsos[SuperGlobals.max_rgroups], gprstd[SuperGlobals.max_rgroups], prescribedfire[SuperGlobals.max_rgroups], + spp[SuperGlobals.max_spp_per_grp * SuperGlobals.max_rgroups], + indv[SuperGlobals.max_spp_per_grp * SuperGlobals.max_rgroups]; + + char buf[2048], tbuf[2048]; // Two buffers: one for accumulating and one for formatting. + char sep = BmassFlags.sep; // Separator specified in inputs + + FILE* file; + file = fopen(filename, "w"); + + buf[0]='\0'; + + load_cell(0, 0); + + if(BmassFlags.header){ + make_header_with_std(buf); + fprintf(file, "%s", buf); + } + + for(year = 0; year < SuperGlobals.runModelYears; ++year){ + *buf = '\0'; //Initialize buffer as empty string + + /* -------- Initialize all accumulators to 0 ------- */ + nobs = 0; + ppt = 0; + pptstd = 0; + pptsos = 0; + temp = 0; + tempstd = 0; + tempsos = 0; + dist = 0; + wildfire = 0; + ForEachGroup(rg){ + grp[rg] = 0; + grpsos[rg] = 0; + grpstd[rg] = 0; + gsize[rg] = 0; + gpr[rg] = 0; + gprsos[rg] = 0; + gprstd[rg] = 0; + prescribedfire[rg] = 0; + } + ForEachSpecies(sp){ + spp[sp] = 0; + indv[sp] = 0; + } + /* ------ End Initialize all accumulators to 0 ------ */ + + for(i = 0; i < grid_Rows; ++i){ // For each row + for(j = 0; j < grid_Cols; ++j){ // For each column + /* ------------- Accumulate requested output ----------------- */ + nobs++; + if(BmassFlags.ppt) { + + float old_ppt_ave = ppt; + ppt = get_running_mean(nobs, ppt, gridCells[i][j]._Ppt->s[year].ave); + pptsos += get_running_sqr(old_ppt_ave, ppt, gridCells[i][j]._Ppt->s[year].ave); + pptstd = final_running_sd(nobs, pptsos); + } + if(BmassFlags.tmp) { + float old_temp_ave = temp; + temp = get_running_mean(nobs, temp, gridCells[i][j]._Temp->s[year].ave); + tempsos += get_running_sqr(old_temp_ave, temp, gridCells[i][j]._Temp->s[year].ave); + tempstd = final_running_sd(nobs, tempsos); + } + if(BmassFlags.dist) dist += gridCells[i][j]._Dist->s[year].nobs; + if(BmassFlags.grpb) { + if(BmassFlags.wildfire){ + wildfire += gridCells[i][j]._Gwf->wildfire[year]; + } + ForEachGroup(rg){ + float old_grp_ave = grp[rg]; + grp[rg] = get_running_mean(nobs, grp[rg], gridCells[i][j]._Grp[rg].s[year].ave); + grpsos[rg] += get_running_sqr(old_grp_ave, grp[rg], gridCells[i][j]._Grp[rg].s[year].ave); + grpstd[rg] = final_running_sd(nobs, grpsos[rg]); + if(BmassFlags.size){ + gsize[rg] += gridCells[i][j]._Gsize[rg].s[year].ave; + } + if(BmassFlags.pr){ + float old_gpr_ave = gpr[rg]; + gpr[rg] = get_running_mean(nobs, gpr[rg], gridCells[i][j]._Gpr[rg].s[year].ave); + gprsos[rg] += get_running_sqr(old_gpr_ave, gpr[rg], gridCells[i][j]._Gpr[rg].s[year].ave); + gprstd[rg] = final_running_sd(nobs, gprsos[rg]); + } + if(BmassFlags.prescribedfire){ + prescribedfire[rg] += gridCells[i][j]._Gwf->prescribedFire[rg][year]; + } + } // End ForEachGroup + } // End grpb + if(BmassFlags.sppb){ + ForEachSpecies(sp){ + spp[sp] += gridCells[i][j]._Spp[sp].s[year].ave; + if(BmassFlags.indv){ + indv[sp] += gridCells[i][j]._Indv[sp].s[year].ave; + } + } // End ForEachSpecies + } // End sppb + /* ------------ End Accumulate requested output --------------- */ + } // End for each column + } // End for each row + + /* ------------------ Average all accumulators ----------------- */ + dist /= grid_Cells; + wildfire /= grid_Cells; + ForEachGroup(rg){ + gsize[rg] /= grid_Cells; + prescribedfire[rg] /= grid_Cells; + } + ForEachSpecies(sp){ + spp[sp] /= grid_Cells; + indv[sp] /= grid_Cells; + } + /* --------------- End average all accumulators --------------- */ - buf[i] = '\0'; - return TRUE; -} + /* ----------------- Generate output string ------------------- */ + /* buf will hold the entire string. tbuf will format the output */ + if(BmassFlags.yr){ + sprintf(buf,"%d%c", year+1, sep); + } + if(BmassFlags.dist){ + sprintf(tbuf, "%f%c", dist, sep); + strcat(buf, tbuf); + } + if(BmassFlags.ppt){ + sprintf(tbuf, "%f%c%f%c", ppt, sep, pptstd, sep); + strcat(buf, tbuf); + } + if (BmassFlags.pclass) { + sprintf(tbuf, "\"NA\"%c", sep); + strcat(buf, tbuf); + } + if(BmassFlags.tmp){ + sprintf(tbuf, "%f%c%f%c", temp, sep, tempstd, sep); + strcat(buf, tbuf); + } + if(BmassFlags.grpb){ + if(BmassFlags.wildfire){ + sprintf(tbuf, "%f%c", wildfire, sep); + strcat(buf, tbuf); + } + ForEachGroup(rg){ + sprintf(tbuf, "%f%c%f%c", grp[rg], sep, grpstd[rg], sep); + strcat(buf, tbuf); -/***********************************************************/ -static void _read_disturbances_in(void) -{ - // reads the grid disturbances input file - // the file should be something like: "cell,use_fecal_pats,use_ant_mounds,use_animal_burrows,kill_yr" - // there should be no spaces in between, just commas separating the values - // kill_yr will overwrite the kill year for each RGroup in the cell (0 means don't use, a # > 0 means kill everything at this year) - - /* - //printf("inside _read_disturbances_in ()\n"); - - GrpIndex rg; - GroupType *g; - - ForEachGroup(rg) - { - g = RGroup[rg]; - // printf(" rgroup name= %s , killYear:%d, proportion_killed=%f,proportion_recovered=%f ,proportion_grazing=%f \n", - // g->name, g->killyr, g->proportion_killed, g->proportion_recovered, g->proportion_grazing); - } - */ - - FILE *f; - char buf[1024]; - int i, cell, num; - - f = OpenFile(grid_files[2], "r"); - - GetALine2(f, buf, 1024); // gets rid of the first line (since it just defines the columns) - for (i = 0; i < grid_Cells; i++) - { - if (!GetALine2(f, buf, 1024)) - break; - - num = sscanf(buf, "%d,%d,%d,%d,%d,%d,%d,%d,%f,%d,%d,%d", &cell, - &grid_Disturb[i].choices[0], &grid_Disturb[i].choices[1], - &grid_Disturb[i].choices[2], &grid_Disturb[i].kill_yr, - &grid_Disturb[i].killfrq, &grid_Disturb[i].extirp, - &grid_Disturb[i].killfreq_startyr,&grid_Disturb[i].xgrow,&grid_Disturb[i].veg_prod_type, - &grid_Disturb[i].grazing_frq,&grid_Disturb[i].grazingfreq_startyr); - - // Convert to SOILWAT2 vegetation index - grid_Disturb[i].veg_prod_type = get_SW2_veg_index(grid_Disturb[i].veg_prod_type); - -// printf("values : cell=%d ,choices[0]=%d ,choices[1]=%d ,choices[2]=%d ,kill_yr=%d ,killfrq=%d ,extirp=%d ,killfreq_startyr=%d ,xgrow=%f ,veg_prod_type=%d ,grazing_frq=%d ,grazingfrd_start_year=%d \n", cell, -// grid_Disturb[i].choices[0], grid_Disturb[i].choices[1], -// grid_Disturb[i].choices[2], grid_Disturb[i].kill_yr, -// grid_Disturb[i].killfrq, grid_Disturb[i].extirp, -// grid_Disturb[i].killfreq_startyr,grid_Disturb[i].xgrow,grid_Disturb[i].veg_prod_type, -// grid_Disturb[i].grazing_frq,grid_Disturb[i].grazingfreq_startyr); - - - if (num != 12) - LogError(logfp, LOGFATAL, "Invalid %s file line %d wrong", - grid_files[2], i + 2); - } - if (i != grid_Cells) - LogError(logfp, LOGFATAL, "Invalid %s file wrong number of cells", - grid_files[2]); - - CloseFile(&f); -} - -/***********************************************************/ -static int _get_value_index(char* s, char seperator, int nSeperators) -{ - //pretty much this function goes through s until it find nSeperators worth of seperators and then returns the index of the next character - //this is used to do most of the parsing in the _read_soils_in() function - int i = 0, sep = 0; - while (*s) - { - i++; - if (*s++ == seperator) //checks if the current char equals the seperator... and then increments the char pointer - if (++sep == nSeperators) //needs ++sep, not sep++ - break; - } - return i; -} - -static int _get_value_index2(char* s, int nSeperators) -{ - //pretty much this function goes through s until it find nSeperators worth of seperators and then returns the index of the next character - //this is used to do most of the parsing in the _read_soils_in() function - int i = 0, sep = 0; - while (1) - { - i++; - if (*s++ == '\0') //checks if the current char equals the seperator... and then increments the char pointer - if (++sep == nSeperators) //needs ++sep, not sep++ - break; - } - return i; -} - -/***********************************************************/ -static void _read_soils_in(void) -{ - // reads the grid soils input - // the file should be something like: "cell,copy_cell,copy_which,num_layers,..." - // there should be no spaces in between, just commas separating the values - // this function reads in pretty much a .csv file, but it will not account for all of the possibilities that a .csv file could be written as (as accounting for all these possibilities would take a while to code and be unproductive) so keep that in mind - - FILE *f; - char buf[4096]; - char rootsin[20]; - char seps[] = ","; - char *token; - int i, j, k, cell, num, do_copy, copy_cell, num_layers, depth, depthMin, - stringIndex; - float d[11]; - - if (sd_Option2a || sd_Option2b) - nSoilTypes = 0; //initialize our soil types counter - - f = OpenFile(grid_files[3], "r"); - - GetALine2(f, buf, 4096); // gets rid of the first line (since it just defines the columns)... it's only there for user readability - for (i = 0; i < grid_Cells; i++) - { - if (!GetALine2(f, buf, 4096)) - break; - - grid_Soils[i].rootsFile[0] = '\0'; - rootsin[0] = '\0'; - - num = 0; - token = strtok(buf, seps); - while (token != NULL && num < 5) - { - switch (num) - { - case 0: - cell = atoi(token); - break; - case 1: - do_copy = atoi(token); - break; - case 2: - copy_cell = atoi(token); - break; - case 3: - num_layers = atoi(token); - break; - case 4: - strcpy(rootsin, token); - break; - } - num++; - if (num != 5) - token = strtok(NULL, seps); - } - - if (num < 5) - if (!do_copy) - LogError(logfp, LOGFATAL, "Invalid %s file", grid_files[3]); - if (!do_copy) - stringIndex = _get_value_index2(buf, 5); //gets us the index of the string that is right after what we just parsed in - - if (num_layers > MAX_LAYERS) - LogError(logfp, LOGFATAL, - "Invalid %s file line %d num_layers (%d) exceeds MAX_LAYERS (%d)", - grid_files[3], i + 2, num_layers, MAX_LAYERS); - - if (do_copy == 1 && copy_cell > -1 && copy_cell < grid_Cells - && cell != 0 && copy_cell < cell) - { //copy this cells values from a previous cell's - grid_Soils[i].lyr = Mem_Calloc(grid_Soils[copy_cell].num_layers, - sizeof(Grid_Soil_Lyr), "_read_soils_in()"); - for (j = 0; j < grid_Soils[copy_cell].num_layers; j++) - grid_Soils[i].lyr[j] = grid_Soils[copy_cell].lyr[j]; - grid_Soils[i].num_layers = grid_Soils[copy_cell].num_layers; - - if (sd_Option2a || sd_Option2b) - grid_SoilTypes[cell] = grid_SoilTypes[copy_cell]; - - strcpy(grid_Soils[i].rootsFile, grid_Soils[copy_cell].rootsFile); - - continue; - } - else if (do_copy == 1) - LogError(logfp, LOGFATAL, - "Invalid %s file line %d invalid copy_cell attempt", - grid_files[3], i + 2); - - if (sd_Option2a || sd_Option2b) - { - grid_SoilTypes[cell] = nSoilTypes; - soilTypes_Array[nSoilTypes] = cell; - nSoilTypes++; - } - - depthMin = 0; - grid_Soils[i].num_layers = num_layers; - strcpy(grid_Soils[i].rootsFile, rootsin); - grid_Soils[i].lyr = Mem_Calloc(num_layers, sizeof(Grid_Soil_Lyr), - "_read_soils_in()"); - for (j = 0; j < num_layers; j++) - { - //the idea behind using &buf[stringIndex] is that we start scanning at the point in the string that is right after what we just parsed... the & is there because we have to send sscanf the pointer that points to that location - num = sscanf(&buf[stringIndex], - "%d,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", &depth, &d[0], &d[1], - &d[2], &d[3], &d[4], &d[5], &d[6], &d[7], &d[8], &d[9], - &d[10]); - if (num != 12) - LogError(logfp, LOGFATAL, - "Invalid '%s' file line %d invalid soil layer input", - grid_files[3], i + 2); - - k = stringIndex; - stringIndex += _get_value_index(&buf[stringIndex], ',', 12); //updates the index of the string that we are at - if (k == stringIndex) - LogError(logfp, LOGFATAL, - "Invalid %s file line %d not enough soil layers", - grid_files[3], i + 2); - - for (k = 0; k < 11; k++) - grid_Soils[i].lyr[j].data[k] = d[k]; - grid_Soils[i].lyr[j].width = depth - depthMin; - depthMin = depth; - } - } - - if (i != grid_Cells) - LogError(logfp, LOGFATAL, "Invalid %s file, not enough cells", - grid_files[3]); - - /*for(i = 0; i < grid_Cells; i++) { - printf("cell %d:\n", i); - for(j = 0; j < grid_Soils[i].num_layers; j++) { - printf("layer %d : %d", j, grid_Soils[i].lyr[j].width); - for(k = 0; k < 11; k++) printf(" %f", grid_Soils[i].lyr[j].data[k]); - printf("\n"); - } - }*/ - - CloseFile(&f); -} - -/***********************************************************/ -static void _init_soil_layers(int cell, int isSpinup) -{ - // initializes the soilwat soil layers for the cell correctly based upon the input gathered from our grid_soils input file - // pretty much takes the data from grid_Soils (read in in _read_soils_in()) and converts it to what SW_Site needs... - // this function does generally the same things that the _read_layers() function in SW_Site.c does, except that it does it in a way that lets us use it in the grid... - int i, j; - i = cell; - char* errtype; - Bool evap_ok = TRUE, transp_ok_forb = TRUE, transp_ok_tree = TRUE, - transp_ok_shrub = TRUE, transp_ok_grass = TRUE; /* mitigate gaps in layers */ - Bool fail = FALSE; - RealF fval = 0; - - if (SW_Site.deepdrain) - SW_Site.n_layers++; - for (j = 0; j < SW_Site.n_layers; j++) - Mem_Free(SW_Site.lyr[j]); - Mem_Free(SW_Site.lyr); - - SW_Site.n_layers = grid_Soils[i].num_layers; - SW_Site.n_evap_lyrs = SW_Site.n_transp_lyrs[SW_FORBS] = - SW_Site.n_transp_lyrs[SW_TREES] = SW_Site.n_transp_lyrs[SW_SHRUB] = - SW_Site.n_transp_lyrs[SW_GRASS] = 0; - - SW_Site.lyr = Mem_Calloc(SW_Site.n_layers + SW_Site.deepdrain, - sizeof(SW_LAYER_INFO *), "_init_grid_globals()"); - for (j = 0; j < SW_Site.n_layers; j++) - { - if (LT(grid_Soils[i].lyr[j].data[0], 0.)) - { - fail = TRUE; - fval = grid_Soils[i].lyr[j].data[0]; - errtype = Str_Dup("bulk density"); - } - else if (LT(grid_Soils[i].lyr[j].data[1], - 0.) || GT(grid_Soils[i].lyr[j].data[1], 1.0)) - { - fail = TRUE; - fval = grid_Soils[i].lyr[j].data[1]; - errtype = Str_Dup("gravel content"); - } - else if (LE(grid_Soils[i].lyr[j].data[7], 0.)) - { - fail = TRUE; - fval = grid_Soils[i].lyr[j].data[7]; - errtype = Str_Dup("sand proportion"); - } - else if (LE(grid_Soils[i].lyr[j].data[8], 0.)) - { - fail = TRUE; - fval = grid_Soils[i].lyr[j].data[8]; - errtype = Str_Dup("clay proportion"); - } - else if (LT(grid_Soils[i].lyr[j].data[9], 0.)) - { - fail = TRUE; - fval = grid_Soils[i].lyr[j].data[9]; - errtype = Str_Dup("impermeability"); - } - if (fail) - { - LogError(logfp, LOGFATAL, "Invalid %s (%5.4f) in layer %d.\n", - errtype, fval, j + 1); - } - - SW_Site.lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_init_grid_globals()"); - - //indexes (for grid_Soils[i].lyr[j].data): - //0 1 2 3 4 5 6 7 8 9 10 - //matricd gravel_content evco trco_grass trco_shrub trco_tree trco_forb %sand %clay imperm soiltemp - SW_Site.lyr[j]->width = grid_Soils[i].lyr[j].width; - SW_Site.lyr[j]->soilMatric_density = grid_Soils[i].lyr[j].data[0]; - SW_Site.lyr[j]->fractionVolBulk_gravel = grid_Soils[i].lyr[j].data[1]; - SW_Site.lyr[j]->evap_coeff = grid_Soils[i].lyr[j].data[2]; - SW_Site.lyr[j]->transp_coeff[3] = grid_Soils[i].lyr[j].data[3]; - SW_Site.lyr[j]->transp_coeff[1] = grid_Soils[i].lyr[j].data[4]; - SW_Site.lyr[j]->transp_coeff[0] = grid_Soils[i].lyr[j].data[5]; - SW_Site.lyr[j]->transp_coeff[2] = grid_Soils[i].lyr[j].data[6]; - SW_Site.lyr[j]->fractionWeightMatric_sand = - grid_Soils[i].lyr[j].data[7]; - SW_Site.lyr[j]->fractionWeightMatric_clay = - grid_Soils[i].lyr[j].data[8]; - SW_Site.lyr[j]->impermeability = grid_Soils[i].lyr[j].data[9]; - SW_Site.lyr[j]->my_transp_rgn[0] = 0; - SW_Site.lyr[j]->my_transp_rgn[2] = 0; - SW_Site.lyr[j]->my_transp_rgn[1] = 0; - SW_Site.lyr[j]->my_transp_rgn[3] = 0; - SW_Site.lyr[j]->sTemp = grid_Soils[i].lyr[j].data[10]; - - if (evap_ok) - { - if (GT(SW_Site.lyr[j]->evap_coeff, 0.0)) - SW_Site.n_evap_lyrs++; - else - evap_ok = FALSE; - } - if (transp_ok_tree) - { - if (GT(SW_Site.lyr[j]->transp_coeff[0], 0.0)) - SW_Site.n_transp_lyrs[SW_TREES]++; - else - transp_ok_tree = FALSE; - } - if (transp_ok_shrub) - { - if (GT(SW_Site.lyr[j]->transp_coeff[1], 0.0)) - SW_Site.n_transp_lyrs[SW_SHRUB]++; - else - transp_ok_shrub = FALSE; - } - if (transp_ok_grass) - { - if (GT(SW_Site.lyr[j]->transp_coeff[3], 0.0)) - SW_Site.n_transp_lyrs[SW_GRASS]++; - else - transp_ok_grass = FALSE; - } - if (transp_ok_forb) - { - if (GT(SW_Site.lyr[j]->transp_coeff[2], 0.0)) - SW_Site.n_transp_lyrs[SW_FORBS]++; - else - transp_ok_forb = FALSE; - } - water_eqn(SW_Site.lyr[j]->fractionVolBulk_gravel, - SW_Site.lyr[j]->fractionWeightMatric_sand, - SW_Site.lyr[j]->fractionWeightMatric_clay, j); //in SW_Site.c, called to initialize some layer data... - SW_Site.lyr[j]->swcBulk_fieldcap = SW_SWPmatric2VWCBulk( - SW_Site.lyr[j]->fractionVolBulk_gravel, 0.333, j) - * SW_Site.lyr[j]->width; - SW_Site.lyr[j]->swcBulk_wiltpt = SW_SWPmatric2VWCBulk( - SW_Site.lyr[j]->fractionVolBulk_gravel, 15, j) - * SW_Site.lyr[j]->width; - //From calculate_soilBulkDensity in SW_Site.c - SW_Site.lyr[j]->soilBulk_density = SW_Site.lyr[j]->soilMatric_density - * (1 - SW_Site.lyr[j]->fractionVolBulk_gravel) - + (SW_Site.lyr[j]->fractionVolBulk_gravel * 2.65); - //already checked for max_layers condition - } - if (SW_Site.deepdrain) - { - SW_Site.n_layers++; - SW_Site.lyr[j] = Mem_Calloc(1, sizeof(SW_LAYER_INFO), - "_init_grid_globals()"); - SW_Site.lyr[j]->width = 1.0; - } - - init_site_info(); //in SW_Site.c, called to initialize layer data... - - free_all_sxw_memory(); - _init_SXW_inputs(FALSE, grid_Soils[i].rootsFile); //we call this so that SXW can set the correct sizes/values up for the memory dynamically allocated in sxw.c - - if (!isSpinup) - { - - grid_SXW_ptrs[i].roots_max = Mem_Calloc(SXW.NGrps * SXW.NTrLyrs, - sizeof(RealD), "_init_soil_layers()"); - grid_SXW_ptrs[i].rootsXphen = Mem_Calloc( - SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - grid_SXW_ptrs[i].roots_active = Mem_Calloc( - SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - grid_SXW_ptrs[i].roots_active_rel = Mem_Calloc( - SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - grid_SXW_ptrs[i].roots_active_sum = Mem_Calloc( - 4 * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - grid_SXW_ptrs[i].phen = Mem_Calloc(SXW.NGrps * MAX_MONTHS, - sizeof(RealD), "_init_soil_layers()"); - grid_SXW_ptrs[i].prod_bmass = Mem_Calloc(SXW.NGrps * MAX_MONTHS, - sizeof(RealD), "_init_soil_layers()"); - grid_SXW_ptrs[i].prod_pctlive = Mem_Calloc(SXW.NGrps * MAX_MONTHS, - sizeof(RealD), "_init_soil_layers()"); - - save_sxw_memory(grid_SXW_ptrs[i].roots_max, grid_SXW_ptrs[i].rootsXphen, - grid_SXW_ptrs[i].roots_active, - grid_SXW_ptrs[i].roots_active_rel, - grid_SXW_ptrs[i].roots_active_sum, grid_SXW_ptrs[i].phen, - grid_SXW_ptrs[i].prod_bmass, grid_SXW_ptrs[i].prod_pctlive); - } - else - { - - spinup_SXW_ptrs[i].roots_max = Mem_Calloc(SXW.NGrps * SXW.NTrLyrs, - sizeof(RealD), "_init_soil_layers()"); - spinup_SXW_ptrs[i].rootsXphen = Mem_Calloc( - SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - spinup_SXW_ptrs[i].roots_active = Mem_Calloc( - SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - spinup_SXW_ptrs[i].roots_active_rel = Mem_Calloc( - SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - spinup_SXW_ptrs[i].roots_active_sum = Mem_Calloc( - 4 * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), - "_init_soil_layers()"); - spinup_SXW_ptrs[i].phen = Mem_Calloc(SXW.NGrps * MAX_MONTHS, - sizeof(RealD), "_init_soil_layers()"); - spinup_SXW_ptrs[i].prod_bmass = Mem_Calloc(SXW.NGrps * MAX_MONTHS, - sizeof(RealD), "_init_soil_layers()"); - spinup_SXW_ptrs[i].prod_pctlive = Mem_Calloc(SXW.NGrps * MAX_MONTHS, - sizeof(RealD), "_init_soil_layers()"); - - save_sxw_memory(spinup_SXW_ptrs[i].roots_max, - spinup_SXW_ptrs[i].rootsXphen, spinup_SXW_ptrs[i].roots_active, - spinup_SXW_ptrs[i].roots_active_rel, - spinup_SXW_ptrs[i].roots_active_sum, spinup_SXW_ptrs[i].phen, - spinup_SXW_ptrs[i].prod_bmass, spinup_SXW_ptrs[i].prod_pctlive); - } -} - -/***********************************************************/ -static float _read_a_float(FILE *f, char *buf, const char *filename, - const char *descriptor) -{ - //small function to reduce code duplication in the _read_seed_dispersal_in() function... - //f should be already open, and all of the character arrays should be pre-allocated before calling the function... - float result; - - if (!GetALine(f, buf)) - LogError(logfp, LOGFATAL, "Invalid %s file: %s", filename, descriptor); - if (sscanf(buf, "%f", &result) != 1) - LogError(logfp, LOGFATAL, "Invalid %s file: %s", filename, descriptor); - - return result; -} - -/***********************************************************/ -static float _cell_dist(int row1, int row2, int col1, int col2, float cellLen) -{ - //returns the distance between the two grid cells - if (row1 == row2) - { - return (abs(col1-col2) * cellLen); - } - else if (col1 == col2) - { - return (abs(row1-row2) * cellLen); - } - else - { // row1 != row2 && col1 != col2 - //the problem can be thought of in terms of a right triangle... - //using the pythagorean theorem: c = sqrt(a^2 + b^2)... c (the hypotenuse) represents the distance that we need. a is the distance between columns and b is the distance between rows. - return sqrt( - pow(abs(col1-col2)*cellLen, 2.0) + pow(abs(row1-row2)*cellLen, 2.0)); - } -} - -/***********************************************************/ -static void _read_seed_dispersal_in(void) -{ - // reads the grid seed dispersal input file and sets up grid_SD with the correct values and probabilities - - FILE *f; - char buf[1024]; - float sd_Rate, H, VW, VT, MAXD, plotLength, d, pd; - int maxCells, i, j, k, MAXDP, row, col, cell; - SppIndex s; - - // read in the seed dispersal input file to get the constants that we need - f = OpenFile(grid_files[4], "r"); - - VW = _read_a_float(f, buf, grid_files[4], "VW line"); - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_DoOutput) != 1) - LogError(logfp, LOGFATAL, - "Invalid %s file: seed dispersal output line\n", grid_files[4]); - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_MakeHeader) != 1) - LogError(logfp, LOGFATAL, - "Invalid %s file: seed dispersal make header line\n", - grid_files[4]); - - GetALine(f, buf); - if (sscanf(buf, "%c", &sd_Sep) != 1) - LogError(logfp, LOGFATAL, - "Invalid %s file: seed dispersal seperator line\n", - grid_files[4]); - - if (sd_Sep == 't') //dealing with tab and space special cases... - sd_Sep = '\t'; - else if (sd_Sep == 's') - sd_Sep = ' '; - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_NYearsSeedsAvailable) != 1) - LogError(logfp, LOGFATAL, "Invalid %s file: option 1 line\n", - grid_files[4]); - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_Option1a) != 1) - LogError(logfp, LOGFATAL, "Invalid %s file: option 1a line\n", - grid_files[4]); - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_Option1b) != 1) - LogError(logfp, LOGFATAL, "Invalid %s file: option 1b line\n", - grid_files[4]); - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_Option2a) != 1) - LogError(logfp, LOGFATAL, "Invalid %s file: option 2a line\n", - grid_files[4]); - - GetALine(f, buf); - if (sscanf(buf, "%d", &sd_Option2b) != 1) - LogError(logfp, LOGFATAL, "Invalid %s file: option 2b line\n", - grid_files[4]); - - if ((sd_Option1a && (sd_Option1b || sd_Option2a || sd_Option2b)) - || (sd_Option2a && (sd_Option1a || sd_Option1b || sd_Option2b))) - LogError(logfp, LOGFATAL, - "Invalid %s file: conflicting options chosen\n", grid_files[4]); - - CloseFile(&f); - - ForEachSpecies(s) - { - // set up grid_SD with the seed dispersal probabilities needed later on... - H = Species[s]->sd_H; - VT = Species[s]->sd_VT; - MAXD = ((H * VW) / VT) / 100.0; // divide by 100.0 because we want it in meters, not centimeters - sd_Rate = -(log(0.05) / MAXD); //sd_Rate is the seed dispersal rate... 0.05 = exp(-RATE*MAXD) => RATE = -(ln(0.05)/MAXD) See Coffin et al. 1993 - - plotLength = sqrt(Globals.plotsize); - MAXDP = (int) ceil(MAXD / plotLength); //MAXD in terms of plots... rounds up to the nearest integer - maxCells = (int) pow((MAXDP * 2) + 1.0, 2.0); //gets the maximum number of cells that a grid cell can possibly disperse seeds to... it ends up being more then the maximum actually... - if (grid_Cells < maxCells) - maxCells = grid_Cells; - if (!(Species[s]->use_me && Species[s]->use_dispersal)) - continue; - - for (i = 0; i < grid_Cells; i++) - { - grid_SD[s][i].cells = Mem_Calloc(maxCells, sizeof(int), - "_read_seed_dispersal_in()"); //the cell number - grid_SD[s][i].prob = Mem_Calloc(maxCells, sizeof(float), - "_read_seed_dispersal_in()"); //the probability that the cell will disperse seeds to this distance - grid_SD[s][i].size = 0; //refers to the number of cells reachable... - } - - for (row = 1; row <= grid_Rows; row++) - for (col = 1; col <= grid_Cols; col++) - { - - cell = col + ((row - 1) * grid_Cols) - 1; - k = 0; - - for (i = 1; i <= grid_Rows; i++) - for (j = 1; j <= grid_Cols; j++) - { - if (i == row && j == col) - continue; - - d = _cell_dist(i, row, j, col, plotLength); //distance - pd = (d > MAXD) ? (0.0) : (exp(-sd_Rate * d)); //dispersal probability - - if (!ZRO(pd)) - { - grid_SD[s][cell].cells[k] = i - + ((j - 1) * grid_Cols) - 1; - grid_SD[s][cell].prob[k] = pd; - grid_SD[s][cell].size++; - k++; - //fprintf(stderr, "cell: %d; i: %d; j: %d; dist: %f; pd: %f %d %d\n", i + ( (j-1) * grid_Cols) - 1, i, j, d, pd, row, col); - } - } - //fprintf(stderr, "size %d index %d maxsize %d\n", grid_SD[cell].size, cell, maxCells); - } - - for (i = 0; i < grid_Cells; i++) - if (grid_SD[s][i].size > 0) - { - grid_SD[s][i].cells = Mem_ReAlloc(grid_SD[s][i].cells, - grid_SD[s][i].size * sizeof(int)); - grid_SD[s][i].prob = Mem_ReAlloc(grid_SD[s][i].prob, - grid_SD[s][i].size * sizeof(float)); - } - } -} - -/***********************************************************/ -static void _do_seed_dispersal(void) -{ - float biomass, randomN, LYPPT, presentProb, receivedProb; - int i, j, germ, sgerm, year; - SppIndex s; - - if (Globals.currYear == 1 && !sd_Option1a && !sd_Option1b) - { //since we have no previous data to go off of, use the current years... - for (i = 0; i < grid_Cells; i++) - ForEachSpecies(s) - { - if (!(Species[s]->use_me && Species[s]->use_dispersal)) - continue; - grid_Species[s][i].allow_growth = grid_Species[s][i].sd_sgerm = - 1;// since it's the first year, we have to allow growth... - if (UseDisturbances) - if (1 == grid_Disturb[i].kill_yr) - grid_Species[s][i].allow_growth = 0; - grid_SD[s][i].lyppt = grid_Env[i].ppt; - } - } - else - { - // figure out whether or not to allow growth for the current year... based upon whether the species already has plants or germination allowed this year and seeds received last year... - ForEachSpecies(s) - { - - if (!(Species[s]->use_me && Species[s]->use_dispersal)) - continue; - - // germination probability - randomN = RandUni(&grid_rng); - germ = LE(randomN, Species[s]->seedling_estab_prob); - - year = Globals.currYear - 1; - - for (i = 0; i < grid_Cells; i++) - { - - if (sd_Option1a && Globals.currYear <= sd_NYearsSeedsAvailable) - { - grid_SD[s][i].seeds_present = 1; + if(BmassFlags.size){ + sprintf(tbuf, "%f%c", gsize[rg], sep); + strcat(buf, tbuf); } - else if (sd_Option1b - && Globals.currYear <= sd_NYearsSeedsAvailable - && grid_initSpecies[i].species_seed_avail[s]) - { - grid_SD[s][i].seeds_present = 1; + if(BmassFlags.pr){ + sprintf(tbuf, "%f%c%f%c", gpr[rg], sep, gprstd[rg], sep); + strcat(buf, tbuf); } - - sgerm = (grid_SD[s][i].seeds_present - || grid_SD[s][i].seeds_received) && germ; //refers to whether the species has seeds available from the previous year and conditions are correct for germination this year - grid_Species[s][i].allow_growth = FALSE; - biomass = getSpeciesRelsize(s) - * grid_Species[s][i].mature_biomass; - - if (UseDisturbances) - { - if ((sgerm || year < grid_Disturb[i].kill_yr - || grid_Disturb[i].kill_yr <= 0 || GT(biomass, 0.0)) - /*&& (year != grid_Disturb[i].kill_yr)*/) - { - //commented above one condition as it was causing a bug there, next year of killing year will make - //allow_growth flag to false as year = Globals.currYear - 1 , so for example if killing year= 6 and Globals.currYear=7 then here - // year variable will be 7-1 =6 that is equal to killing year 6, so this condition (year != grid_Disturb[i].kill_yr) - //will fail and allow_growth will not become TRUE, then when Globals.currYear=8 this allow_growth= FALSE will carry forward and there will no call - // to other functions. Last year size will carry forward so in final output year 7 and year 8 will - // have same output that is not correct. - grid_Species[s][i].allow_growth = TRUE; - } - + if(BmassFlags.prescribedfire){ + sprintf(tbuf, "%f%c", prescribedfire[rg], sep); + strcat(buf, tbuf); } - else if (sgerm || GT(biomass, 0.0)) - grid_Species[s][i].allow_growth = TRUE; - grid_Species[s][i].sd_sgerm = sgerm; //based upon whether we have received/produced seeds that germinated - //if(grid_Species[s][i].allow_growth == TRUE && i == 52 && s == 0 && Globals.currIter == 1) - // printf("%s allow_growth:%d year:%d sgerm:%d iter:%d\n", grid_Species[s][i].name, grid_Species[s][i].allow_growth, year, sgerm, Globals.currIter); } } - - } - - // calculate whether or not seeds were received/produced this year, this data is used the next time the function is called - ForEachSpecies(s) - { - if (!(Species[s]->use_me && Species[s]->use_dispersal)) - continue; - - IndivType* indiv; - - // figure out which species in each cell produced seeds... - for (i = 0; i < grid_Cells; i++) - { - grid_SD[s][i].seeds_present = grid_SD[s][i].seeds_received = - grid_Species[s][i].received_prob = 0; - - biomass = 0; //getting the biggest individual in the species... - ForEachIndiv(indiv, &grid_Species[s][i]) - if (indiv->relsize * grid_Species[s][i].mature_biomass - > biomass) - biomass = indiv->relsize - * grid_Species[s][i].mature_biomass; - - if (GE(biomass, - grid_Species[s][i].mature_biomass - * grid_Species[s][i].sd_Param1)) - { - randomN = RandUni(&grid_rng); - - LYPPT = grid_SD[s][i].lyppt; - float PPTdry = grid_Species[s][i].sd_PPTdry, PPTwet = - grid_Species[s][i].sd_PPTwet; - float Pmin = grid_Species[s][i].sd_Pmin, Pmax = - grid_Species[s][i].sd_Pmax; - - //p3 = Pmin, if LYPPT < PPTdry - //p3 = 1 - (1-Pmin) * exp(-d * (LYPPT - PPTdry)) with d = - ln((1 - Pmax)/(1 - Pmin)) / (PPTwet - PPTdry), if PPTdry <= LYPPT <= PPTwet - //p3 = Pmax, if LYPPT > PPTwet - - presentProb = 0.0; - if (PPTdry <= LYPPT && LYPPT <= PPTwet) - { - float d = -log(((1 - Pmax) / (1 - Pmin))) - / (PPTwet - PPTdry); //log is the natural log in STD c's math.h - presentProb = 1 - (1 - Pmin) * exp((-d * (LYPPT - PPTdry))); + if(BmassFlags.sppb){ + ForEachSpecies(sp){ + sprintf(tbuf, "%f%c", spp[sp], sep); + strcat(buf, tbuf); + if(BmassFlags.indv){ + sprintf(tbuf, "%f%c", indv[sp], sep); + strcat(buf, tbuf); } - else if (LYPPT < PPTdry) - presentProb = Pmin; - else if (LYPPT > PPTwet) - presentProb = Pmax; - - if (LE(randomN, presentProb)) - grid_SD[s][i].seeds_present = 1; } - //if(i == 0) printf("cell: %d lyppt: %f\n", i, grid_SD[i].lyppt); - } - - // figure out which species in each cell received seeds... - for (i = 0; i < grid_Cells; i++) - { - if (grid_SD[s][i].seeds_present) - continue; - receivedProb = 0; - - for (j = 0; j < grid_SD[s][i].size; j++) - if (grid_SD[s][grid_SD[s][i].cells[j]].seeds_present) - receivedProb += grid_SD[s][i].prob[j]; - - randomN = RandUni(&grid_rng); - if (LE(randomN, receivedProb) && !ZRO(receivedProb)) - grid_SD[s][i].seeds_received = 1; - else - grid_SD[s][i].seeds_received = 0; - - grid_Species[s][i].received_prob = receivedProb; } - } -} - -/***********************************************************/ -static void _set_sd_lyppt(int row, int col) -{ - int cell = col + ((row - 1) * grid_Cols) - 1; - SppIndex s; - - ForEachSpecies(s) - if (Species[s]->use_me && Species[s]->use_dispersal) - grid_SD[s][cell].lyppt = grid_Env[cell].ppt; -} - - -/* - * - */ - -static void _do_groups_and_species_extirpate(void) -{ - //printf("inside _do_groups_and_species_extirpate()\n"); - GrpIndex rg; - ForEachGroup(rg) - { - rgroup_Extirpate(rg); - } -} - -/***********************************************************/ -static void _kill_groups_and_species(void) -{ - /* (AKT /Kyle) 11/17/2016 - *we may need to revisit this setting PR to 0 when we kill everything - *ForEachGroup(c) - *RGroup[c]->pr = 0.0; // reset the pr, so our output doesn't look weird - */ - - //printf("inside _kill_groups_and_species()\n"); - GrpIndex rg; - ForEachGroup(rg) - { - if (Globals.currYear < RGroup[rg]->startyr) - { - /* don't start trying to kill until RGroup[rg]->startyr year as nothing grow till now */ - continue; - } - Int i; - - ForEachEstSpp2( rg, i) - { - if (!Species[RGroup[rg]->est_spp[i]]->use_me) - { - continue; - } - else - { - // printf("calling Species_Proportion_Kill() with rgroup name= %s , RGroup[%d]->proportion_killed =%f for Species[%d]->name= %s \n",RGroup[rg]->name,rg, RGroup[rg]->proportion_killed, i, Species[RGroup[rg]->est_spp[i]]->name); - Species_Proportion_Kill(RGroup[rg]->est_spp[i], 6, RGroup[rg]->proportion_killed); - } - - } - - } - - -} - -/***********************************************************/ -static int _do_grid_disturbances(int row, int col) -{ - // return 1 if a disturbance occurs, else return 0 - - if(UseDisturbances) - { - int cell = col + ((row - 1) * grid_Cols) - 1; -// printf( "inside _do_grid_disturbances Globals.currYear =%d, cell=%d, grid_Disturb[cell].kill_yr =%d \n", -// Globals.currYear, cell, grid_Disturb[cell].kill_yr); - if ((Globals.currYear >=grid_Disturb[cell].killfreq_startyr) && GT((float)grid_Disturb[cell].killfrq, 0.)) - { - if (LT((float)grid_Disturb[cell].killfrq, 1.0)) - { - if (RandUni(&grid_rng) <= grid_Disturb[cell].killfrq) - { - grid_Disturb[cell].kill_yr = Globals.currYear; - } - - } - else if (((Globals.currYear - grid_Disturb[cell].killfreq_startyr) % (IntU) grid_Disturb[cell].killfrq) == 0) - { - grid_Disturb[cell].kill_yr = Globals.currYear; - } - - } - - if (Globals.currYear == grid_Disturb[cell].extirp) - { - _do_groups_and_species_extirpate(); - return 1; - } - else if (Globals.currYear == grid_Disturb[cell].kill_yr) - { -// printf( "current year matched with cell kill_year so calling _kill_groups_and_species() Globals.currYear =%d, cell=%d, grid_Disturb[cell].kill_yr =%d \n", -// Globals.currYear, cell, grid_Disturb[cell].kill_yr); - _kill_groups_and_species(); - return 1; - } - - - } - return 0; -} + /* --------------- End generate output string ---------------- */ + fprintf(file, "%s\n", buf); // Finally, print this line + } // End for each year -static void _do_grid_proportion_Recovery(int row, int col) -{ - /*======================================================*/ - /* PURPOSE - Perform the sorts of proportion_Recovery one might expect at next year after the killing year - HISTORY - Nov 22 2016 -AKT -Added Species Proportion Recovery for Grid Version */ - /*======================================================*/ - if (UseDisturbances) - { - int cell = col + ((row - 1) * grid_Cols) - 1; -// printf( "inside _do_grid_proportion_Recovery Globals.currYear =%d, cell=%d, grid_Disturb[cell].kill_yr =%d \n", -// Globals.currYear, cell, grid_Disturb[cell].kill_yr); - if ((Globals.currYear >= grid_Disturb[cell].killfreq_startyr) && GT((float)grid_Disturb[cell].killfrq, 0.)) - { - if (LT((float)grid_Disturb[cell].killfrq, 1.0)) - { - if (RandUni(&grid_rng) <= grid_Disturb[cell].killfrq) - { - grid_Disturb[cell].kill_yr = Globals.currYear; - } - - } - else if (((Globals.currYear - grid_Disturb[cell].killfreq_startyr) % (IntU) grid_Disturb[cell].killfrq) == 0) - { - grid_Disturb[cell].kill_yr = Globals.currYear; - } - - } - - //rgroup proportion recovery - if (Globals.currYear == grid_Disturb[cell].kill_yr) - { - GrpIndex rg; - ForEachGroup(rg) - { - if (Globals.currYear < RGroup[rg]->startyr) - { - /* don't start trying to grow until RGroup[rg]->startyr year */ - continue; - } - - Int i; - - ForEachEstSpp2( rg, i) - { - if (!Species[RGroup[rg]->est_spp[i]]->use_me) - { - continue; - } - else - { - // printf( "calling Species_Proportion_Recovery() with rgroup name= %s , RGroup[%d]->proportion_recovered =%f for Species[%d]->name= %s \n", RGroup[rg]->name, rg, RGroup[rg]->proportion_recovered, i, Species[RGroup[rg]->est_spp[i]]->name); - Species_Proportion_Recovery(RGroup[rg]->est_spp[i], 6, - RGroup[rg]->proportion_recovered, - RGroup[rg]->proportion_killed); - } - - } - - } - - } - - } - -} - -static void _do_grid_grazing_EndOfYear(int row, int col) -{ - - /*======================================================*/ - /* PURPOSE - * Perform the sorts of grazing one might expect at end of year, it is based on grazing frequency - * HISTORY - * Nov 22 2016 -AKT -Added Species grazing EndOfYear for grid model - */ - /*======================================================*/ - - if (UseDisturbances) - { - IntU grazingyr = 0; - int cell = col + ((row - 1) * grid_Cols) - 1; - - if ((Globals.currYear >=grid_Disturb[cell].grazingfreq_startyr) && grid_Disturb[cell].grazing_frq > 0.) - { - if (grid_Disturb[cell].grazing_frq < 1.0) - { - if (RandUni(&grid_rng) <= grid_Disturb[cell].grazing_frq) - { - grazingyr = Globals.currYear; - } - - } - else if (((Globals.currYear - grid_Disturb[cell].grazingfreq_startyr) % (IntU) grid_Disturb[cell].grazing_frq) == 0) - { - grazingyr = Globals.currYear; - } - - } - - //rgroup proportion grazing - if (Globals.currYear == grazingyr) - { - GrpIndex rg; - ForEachGroup(rg) - { - if (Globals.currYear < RGroup[rg]->startyr) - { - /* don't start trying to grow or do grazing until RGroup[rg]->startyr year */ - continue; - } - - Int i; - - ForEachEstSpp2( rg, i) - { - if (!Species[RGroup[rg]->est_spp[i]]->use_me) - { - continue; - } - else - { - // printf( "year = %d, calling Species_Proportion_Grazing() with rgroup name= %s , RGroup[%d]->proportion_grazing =%f for Species[%d]->name= %s \n", Globals.currYear,RGroup[rg]->name, rg,RGroup[rg]->proportion_grazing, i, Species[RGroup[rg]->est_spp[i]]->name); - Species_Proportion_Grazing(RGroup[rg]->est_spp[i], RGroup[rg]->proportion_grazing); - } - - } - - } - - } - - } - -} - -/***********************************************************/ -static void _read_init_species(void) -{ - // reads the grid init species input - // the file should be something like: "cell,copy_cell,copy_which,use_SpinUp,(all the species names seperated by a comma)" - // there should be no spaces in between, just commas separating the values (ie it should be a .csv file, but does not account for all of the possibilities that a .csv file could be) - - FILE *f; - int i, j, num, cell, do_copy, copy_cell, use_SpinUp, seeds_Avail; - char buf[4096]; - - //open the file/do the reading - f = OpenFile(grid_files[5], "r"); //grid_files[5] is the grid_initSpecies.csv file - - GetALine2(f, buf, 4096); // gets rid of the first line (since it just defines the columns)... it's only there for user readability - for (i = 0; i < grid_Cells; i++) - { - if (!GetALine2(f, buf, 4096)) - break; - - num = sscanf(buf, "%d,%d,%d,%d", &cell, &do_copy, ©_cell, - &use_SpinUp); - if (num != 4) - LogError(logfp, LOGFATAL, "Invalid %s file", grid_files[5]); - - grid_initSpecies[i].use_SpinUp = use_SpinUp; - - int stringIndex = _get_value_index(buf, ',', 4); //gets us the index of the string that is right after what we just parsed in - - if (do_copy == 1 && copy_cell > -1 && copy_cell < grid_Cells - && cell != 0 && copy_cell < cell) - { //copy this cells values from a previous cell's - for (j = 0; j < Globals.sppCount; j++) - grid_initSpecies[i].species_seed_avail[j] = - grid_initSpecies[copy_cell].species_seed_avail[j]; - grid_initSpecies[i].use_SpinUp = - grid_initSpecies[copy_cell].use_SpinUp; - continue; - } - else if (do_copy == 1) - LogError(logfp, LOGFATAL, - "Invalid %s file line %d invalid copy_cell attempt", - grid_files[5], i + 2); - - //going through each species - SppIndex s; - ForEachSpecies(s) - { - num = sscanf(&buf[stringIndex], "%d,", &seeds_Avail); - if (num != 1) - LogError(logfp, LOGFATAL, - "Invalid %s file line %d invalid species input", - grid_files[5], i + 2); - - grid_initSpecies[i].species_seed_avail[s] = seeds_Avail; - stringIndex += _get_value_index(&buf[stringIndex], ',', 1); - } - } - - if (i != grid_Cells) - LogError(logfp, LOGFATAL, "Invalid %s file, not enough cells", - grid_files[5]); - - CloseFile(&f); + unload_cell(); + fclose(file); // Close the file } -#endif \ No newline at end of file +/* Output the average mortality across cells. */ +void _Output_AllCellAvgMort(const char* fileName){ + if (!MortFlags.summary) return; + + /* We need a cell loaded for the ForEach loops. */ + load_cell(0,0); + + FILE *file; + IntS age; + GrpIndex rg; + SppIndex sp; + char sep = MortFlags.sep; + + int row, col, nobs = 0; + + float Gestab[SuperGlobals.max_rgroups], + Sestab[SuperGlobals.max_spp_per_grp * SuperGlobals.max_rgroups], + Gmort[SuperGlobals.max_rgroups][Globals->Max_Age], + Smort[SuperGlobals.max_spp_per_grp * SuperGlobals.max_rgroups][Globals->Max_Age]; + + file = OpenFile( fileName, "w"); + + /* --------------------- Initialize values ----------------------- */ + ForEachSpecies(sp){ + Sestab[sp] = 0; + for(age = 0; age < Globals->Max_Age; ++age){ + Smort[sp][age] = 0; + } + } + ForEachGroup(rg){ + Gestab[rg] = 0; + for(age = 0; age < Globals->Max_Age; ++age){ + Gmort[rg][age] = 0; + } + } + /* ------------------ End initializing values -------------------- */ + + /* ----------------------------- Calculate averaged values ------------------------------------- */ + for(row = 0; row < grid_Rows; row++){ + for(col = 0; col < grid_Cols; col++){ + nobs++; + if (MortFlags.group) { + ForEachGroup(rg){ + Gestab[rg] = get_running_mean(nobs, Gestab[rg], gridCells[row][col]._Gestab[rg].s[0].ave); + } + } + + if (MortFlags.species) { + ForEachSpecies(sp){ + Sestab[sp] = get_running_mean(nobs, Sestab[sp], gridCells[row][col]._Sestab[sp].s[0].ave); + } + } + + /* print one line of kill frequencies per age */ + for(age=0; age < Globals->Max_Age; age++) { + if (MortFlags.group) { + ForEachGroup(rg){ + Gmort[rg][age] = get_running_mean(nobs, Gmort[rg][age], gridCells[row][col]._Gmort[rg].s[age].ave); + } + } + if (MortFlags.species) { + ForEachSpecies(sp) { + Smort[sp][age] = get_running_mean(nobs, Smort[sp][age], gridCells[row][col]._Smort[sp].s[age].ave); + } + } + } + } + } + /* --------------------------- End calculating averaged values -------------------------------- */ + + /* --------------------- Print header ------------------ */ + fprintf(file, "Age"); + if (MortFlags.group) { + ForEachGroup(rg) { + fprintf(file,"%c%s", sep, RGroup[rg]->name); + } + } + if (MortFlags.species) { + ForEachSpecies(sp) + fprintf(file,"%c%s", sep, Species[sp]->name); + } + fprintf(file,"\n"); + fprintf(file,"Estabs"); + /* ---------------------- End header ------------------- */ + + /* --------------------- Print values ------------------ */ + if(MortFlags.group){ + ForEachGroup(rg){ + fprintf(file,"%c%5.1f", sep, Gestab[rg]); + } + } + + if (MortFlags.species) { + ForEachSpecies(sp){ + fprintf(file,"%c%5.1f", sep, Sestab[sp]); + } + } + + fprintf(file,"\n"); + + /* print one line of kill frequencies per age */ + for(age=0; age < Globals->Max_Age; age++) { + fprintf(file,"%d", age+1); + if (MortFlags.group) { + ForEachGroup(rg) + fprintf(file,"%c%5.1f", sep, ( age < GrpMaxAge(rg) ) + ? Gmort[rg][age] + : 0.); + } + if (MortFlags.species) { + ForEachSpecies(sp) { + fprintf(file,"%c%5.1f", sep, ( age < SppMaxAge(sp)) + ? Smort[sp][age] + : 0.); + } + } + fprintf(file,"\n"); + } + /* ----------------- End printing values --------------- */ + + unload_cell(); + CloseFile(&file); +} \ No newline at end of file diff --git a/ST_grid.h b/ST_grid.h new file mode 100644 index 00000000..5be0ec53 --- /dev/null +++ b/ST_grid.h @@ -0,0 +1,167 @@ +/******************************************************************/ +/* ST_grid.h + This header defines global functions, variables, structs and + enumerators from ST_grid.c. If you are looking for the functions + that this module exports check the bottom of the file. + + Initial programming by Chandler Haukap in August 2019. */ +/******************************************************************/ + +#ifndef GRID_H +#define GRID_H + +/******** These modules are necessary to compile ST_grid.c ********/ +#include "ST_stats.h" +#include "ST_defines.h" +#include "sw_src/pcg/pcg_basic.h" +#include "sxw_vars.h" +#include "SW_Site.h" +#include "SW_SoilWater.h" +#include "SW_VegProd.h" +#include "SW_Model.h" +#include "SW_Weather.h" +#include "ST_seedDispersal.h" + +/*********************** Grid Structures ****************************/ + +// Contains the input data for all the soil layers of a cell +struct Soil_st +{ + // Number of soil layers (size of lyr array) + int num_layers; + // Name of the roots file belonging to this cell + char rootsFile[20]; + // Specific layer's information. The size of these arrays is the + // same as num_layers. + RealF *depth; /* Each Layer's max depth */ + RealF *matricd; /* Each Layer's matricx */ + RealF *gravel; /* Each Layer's gravel content */ + RealF *evco; /* Each Layer's evco */ + RealF *trco_grass; /* Each Layer's trco for grass */ + RealF *trco_shrub; /* Each Layer's trco for shrubs */ + RealF *trco_tree; /* Each Layer's trco for tree */ + RealF *trco_forb; /* Each Layer's trco for forbs */ + RealF *psand; /* Each Layer's sand content */ + RealF *pclay; /* Each Layer's clay content */ + RealF *imperm; /* Each layer's impermiability */ + RealF *soiltemp; /* Each Layer's temperature */ +}typedef SoilType; + +/* Initialization information. */ +struct grid_init_species_st +{ + /* TRUE if at least one species has requested initialization */ + int useInitialization; + /* Array of Boolean values. TRUE if given species + should be included in spinup */ + int *shouldBeInitialized; +}typedef Grid_Init_Species_St; + +/* Holds all plot-specific parameters */ +struct grid_cell_st +{ + /* RGroup corresponding to this cell */ + GroupType **myGroup; + /* Species corresponding to this cell */ + SpeciesType **mySpecies; + /* Succulents corresponding to this cell */ + SucculentType mySucculent; + /* This cell's environment. We expect each cell to + * have slightly different weather each year */ + EnvType myEnvironment; + /* Cell's plot data */ + PlotType myPlot; + /* Global variables corresponding to this cell */ + ModelType myGlobals; + /* If TRUE this cell should use seed dispersal */ + Bool useSeedDispersal; + /* TRUE if this cell is in spinup mode */ + Bool DuringInitialization; + /* species spinup information */ + Grid_Init_Species_St mySpeciesInit; + /* seed dispersal information corresponding to this cell */ + Grid_SD_St *mySeedDispersal; + + Bool* someKillage; + + /* ---------------- accumulators -------------------- */ + StatType *_Dist, *_Ppt, *_Temp, + *_Grp, *_Gsize, *_Gpr, *_Gmort, *_Gestab, + *_Spp, *_Indv, *_Smort, *_Sestab, *_Sreceived; + FireStatsType *_Gwf; + Bool stats_init; + /* -------------- end accumulators ------------------ */ + + /* -------------------- SXW ------------------------- */ + transp_t* myTranspWindow; + SXW_t* mySXW; + SXW_resourceType* mySXWResources; + /* ------------------ End SXW ----------------------- */ + + /* ------------------- Soils ------------------------ */ + // Soil layer information for this cell. + SoilType mySoils; + /* ------------------ End Soils --------------------- */ +} typedef CellType; + +/**************************** Enumerators *********************************/ +/* Indices for grid_directories go here */ +typedef enum +{ + GRID_DIRECTORY_STEPWAT_INPUTS, + + /* Automatically generate number of directories since enums start at 0 */ + N_GRID_DIRECTORIES +} Directory_Indices; + +/* Indices for grid_files go here */ +typedef enum +{ + GRID_FILE_LOGFILE, + GRID_FILE_SETUP, + GRID_FILE_DISTURBANCES, + GRID_FILE_SOILS, + GRID_FILE_INIT_SPECIES, + GRID_FILE_FILES, + GRID_FILE_MAXRGROUPSPECIES, + + GRID_FILE_PREFIX_BMASSAVG, + GRID_FILE_PREFIX_MORTAVG, + GRID_FILE_PREFIX_RECEIVEDPROB, + GRID_FILE_PREFIX_BMASSCELLAVG, + GRID_FILE_PREFIX_MORTCELLAVG, + + /* Automatically generate number of files since enums start at 0 */ + N_GRID_FILES +} File_Indices; + +typedef enum +{ + SOIL_READ_SUCCESS = -2, + SOIL_READ_FAILURE = -1, +} Soil_Read_Return_Values; + +/************************ Exported Variable Declarations **************************/ + +/* gridCells[i][j] denotes the cell at position (i,j) */ +CellType** gridCells; +/* Rows in the grid */ +int grid_Rows; +/* Columns in the grid */ +int grid_Cols; +/* Array of file names. Use the File_Indices enum to pick the correct index. */ +char *grid_files[N_GRID_FILES]; +/* Array of directory names. Use the Directory_Indices enum to pick the correct index. */ +char *grid_directories[N_GRID_DIRECTORIES]; +/* TRUE if every cell should write its own output file. */ +Bool writeIndividualFiles; + +/**************************** Exported Functions **********************************/ + +void runGrid(void); +void load_cell(int row, int col); +void unload_cell(void); +void rereadInputs(void); +void free_grid_memory(void); + +#endif \ No newline at end of file diff --git a/ST_indivs.c b/ST_indivs.c index 4267dd07..245ad83a 100644 --- a/ST_indivs.c +++ b/ST_indivs.c @@ -34,6 +34,7 @@ void species_Update_Kills( SppIndex sp, IntS age ); /* places; that is, they are not generally useful */ /* (like C++ friend functions) but have to be declared. */ Bool indiv_New( SppIndex sp); +void copy_individual(const IndivType* src, IndivType* dest); Bool indiv_Kill_Partial( MortalityType code, IndivType *ndv, RealF killamt); @@ -88,11 +89,11 @@ Bool indiv_New( SppIndex sp) { IndivType *p; static int id=0; - if (Species[sp]->est_count == Globals.max_indivs_per_spp) { + if (Species[sp]->est_count == SuperGlobals.max_indivs_per_spp) { LogError(logfp, LOGWARN, "Limit reached: %s is about to get %d " "indivs (max=%d)\n", Species[sp]->name, Species[sp]->est_count +1, - Globals.max_indivs_per_spp); + SuperGlobals.max_indivs_per_spp); } p = _create(); @@ -111,11 +112,37 @@ Bool indiv_New( SppIndex sp) { p->Prev = NULL; Species[sp]->IndvHead = p; + // This functionality is unused, but it might be useful in the future. //sql for inserting new indiv //if(!UseGrid) // insertIndiv(p); + id++; - return( TRUE); + return TRUE; +} + +/* Copy one individual's information to another individual. + Note: this does not modify either individual's linked list functionality. + Both individuals MUST be allocated. */ +void copy_individual(const IndivType* src, IndivType* dest){ + dest->id = src->id; + dest->normal_growth = src->normal_growth; + dest->pr = src->pr; + dest->prob_veggrow = src->prob_veggrow; + dest->prv_yr_relsize = src->prv_yr_relsize; + dest->relsize = src->relsize; + dest->res_avail = src->res_avail; + dest->res_extra = src->res_extra; + dest->res_required = src->res_required; + dest->slow_yrs = src->slow_yrs; + dest->yrs_neg_pr = src->yrs_neg_pr; + dest->age = src->age; + dest->growthrate = src->growthrate; + dest->grp_res_prop = src->grp_res_prop; + dest->killed = src->killed; + dest->killedby = src->killedby; + dest->mm_extra_res = src->mm_extra_res; + dest->myspecies = src->myspecies; } /**************************************************************/ @@ -218,7 +245,7 @@ void indiv_proportion_Kill(IndivType *ndv, int killType, RealF proportKilled) LogError(logfp, LOGWARN, "%s dies older than max_age (%d > %d). Iter=%d, Year=%d\n", Species[ndv->myspecies]->name, ndv->age, Species[ndv->myspecies]->max_age, - Globals.currIter, Globals.currYear); + Globals->currIter, Globals->currYear); } //if (!UseGrid) @@ -345,7 +372,7 @@ void indiv_Kill_Complete( IndivType *ndv, int killType) { LogError(logfp, LOGWARN, "%s dies older than max_age (%d > %d). Iter=%d, Year=%d\n", Species[ndv->myspecies]->name, ndv->age, Species[ndv->myspecies]->max_age, - Globals.currIter, Globals.currYear); + Globals->currIter, Globals->currYear); } // if(!UseGrid) // insertIndivKill(ndv->id,killType); diff --git a/ST_initialization.c b/ST_initialization.c new file mode 100644 index 00000000..4ea0349c --- /dev/null +++ b/ST_initialization.c @@ -0,0 +1,315 @@ +/***********************************************************************/ +// ST_initialization.c +// Contains definitions of all functions related to initialization. +// The current initialization methods are _run_seed_initialization +// and _run_spinup. Note that _run_seed_initialization is non-functional +// as of 12/11/19, but the logic is in place to call the function. This +// file uses the "_" prefix in function names to denote private +// functions that should NEVER be called outside of this file. +// +// TO ADD AN INITIALIZATION METHOD: +// Adding a method is simple. runInitialization() takes care of memory +// management, iterating, and loading cells. All you need to do in your +// new function is define what the program should do for ONE year and +// for ONE cell. Once you have your function written, add an entry for +// it to the InitializationMethod enumerator in ST_initialization.h, +// add your method to _read_grid_setup() of ST_grid.c, then add your +// function to the switch statement in runInitialization(). To see +// an example initialization function check out _run_spinup(). +/***********************************************************************/ + +// ST_initialization.h contains declarations for runInitialization and loadInitializationConditions +#include "ST_initialization.h" +#include "ST_grid.h" +#include "ST_stats.h" +#include "ST_globals.h" +#include "ST_defines.h" +#include "sw_src/pcg/pcg_basic.h" +#include "sw_src/rands.h" +#include "sxw_funcs.h" +#include "myMemory.h" +#include "filefuncs.h" +#include "ST_progressBar.h" +#include "ST_stats.h" + +/********** Local functions. These should all be treated as private. *************/ +static void _run_spinup(void); +static void _run_seed_initialization(void); +static void _beginInitialization(void); +static void _endInitialization(void); +static void _saveAsInitializationConditions(void); + +/***************************** Externed variables **********************************/ +/* Note that in an ideal world we wouldn't need to extern any variables because + every module would declare them in a header file. Hopefully we can get this + cleaned up soon! -CH */ + +// these are SOILWAT variables that we need... +extern SW_SOILWAT SW_Soilwat; +extern SW_SITE SW_Site; +extern SW_VEGPROD SW_VegProd; +extern SW_WEATHER SW_Weather; + +extern pcg32_random_t grid_rng; // Gridded mode's unique RNG. + +/* We need to seed these RNGs when using the gridded mode but do not use them in this file. */ +extern pcg32_random_t environs_rng; // Used exclusively in ST_environs.c +extern pcg32_random_t mortality_rng; // Used exclusively in ST_mortality.c +extern pcg32_random_t resgroups_rng; // Used exclusively in ST_resgroups.c +extern pcg32_random_t species_rng; // Used exclusively in ST_species.c +extern pcg32_random_t markov_rng; // Used exclusively in SW_Markov.c + +extern Bool UseProgressBar; // From ST_main.c +extern Bool* _SomeKillage; // From ST_mortality.c + +/********* Modular functions defined elsewhere ************/ +/* Again, we should clean this up eventually. -CH */ + +void rgroup_Establish(void); +void rgroup_PartResources(void); +void rgroup_Grow(void); +void mort_Main(Bool* killed); +void rgroup_IncrAges(void); +void _kill_annuals(void); +void _kill_maxage(void); +void proportion_Recovery(void); +void _kill_extra_growth(void); +void parm_Initialize(void); +void Plot_Initialize(void); +void copy_rgroup(const GroupType* src, GroupType* dest); +void copy_species(const SpeciesType* src, SpeciesType* dest); + +/* Initializes the plot with whichever method you have specified with initializationMethod. + This function takes care of EVERYTHING involved with initialization. + After calling this function you can load in the initialization information by calling + loadInitializationConditions(). */ +void runInitialization(void){ + _beginInitialization(); + + /* Dummy accumulators to ensure we do not collect statistics */ + StatType *dummy_Dist, *dummy_Ppt, *dummy_Temp, + *dummy_Grp, *dummy_Gsize, *dummy_Gpr, *dummy_Gmort, *dummy_Gestab, + *dummy_Spp, *dummy_Indv, *dummy_Smort, *dummy_Sestab, *dummy_Sreceived; + FireStatsType *dummy_Gwf; + + /* For iterating over gridCells */ + int i, j; + + /* For iterating over years */ + IntS year; + + /* Initialization is technically an iteration so we need to seed the RNGs. */ + RandSeed(SuperGlobals.randseed, &environs_rng); + RandSeed(SuperGlobals.randseed, &mortality_rng); + RandSeed(SuperGlobals.randseed, &resgroups_rng); + RandSeed(SuperGlobals.randseed, &species_rng); + RandSeed(SuperGlobals.randseed, &grid_rng); + RandSeed(SuperGlobals.randseed, &markov_rng); + + // Initialize the plot for each grid cell + for (i = 0; i < grid_Rows; i++){ + for (j = 0; j < grid_Cols; j++){ + load_cell(i, j); + Plot_Initialize(); + Globals->currIter = 1; // Iteration doesn't really matter, I set it to 1 here just in case. + } + } + unload_cell(); // Reset the global variables + + /* Iterate through the number of years requested in inputs. */ + for (year = 1; year <= SuperGlobals.runInitializationYears; year++) + { + if(UseProgressBar){ + logProgress(0, year, INITIALIZATION); // iter = 0 because we are not actually in an iterations loop. + } + for (i = 0; i < grid_Rows; ++i) + { // for each row + for(j = 0; j < grid_Cols; ++j) + { // for each column + // If we should run spinup on this cell + if(gridCells[i][j].mySpeciesInit.useInitialization){ + // Load up a cell + load_cell(i, j); + } else { + continue; // No spinup requested. Move on to next cell. + } + + /* This step is important. load_cell loaded in the actual accumulators, but we do not want + to accumulate stats while in spinup. We need to load in dummy accumulators to ensure + we ignore everything that happens in spinup. */ + stat_Copy_Accumulators(dummy_Dist, dummy_Ppt, dummy_Temp, dummy_Grp, dummy_Gsize, dummy_Gpr, dummy_Gmort, dummy_Gestab, + dummy_Spp, dummy_Indv, dummy_Smort, dummy_Sestab, dummy_Sreceived, dummy_Gwf, TRUE); + + Globals->currYear = year; + + switch (initializationMethod){ + case INIT_WITH_SPINUP: + _run_spinup(); + break; + case INIT_WITH_SEEDS: + _run_seed_initialization(); + break; + default: + break; + } + + } /* end column */ + } /* end row */ + unload_cell(); // Reset the global variables + } /* end model run for this year*/ + + ChDir(grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS]); + SXW_Reset(gridCells[0][0].mySXW->f_watin); + //TODO: This is a shortcut. swc history is not used and shouldn't be until this is fixed. + Mem_Free(SW_Soilwat.hist.file_prefix); + SW_Soilwat.hist.file_prefix = NULL; + ChDir(".."); + + _endInitialization(); +} + +/* Prepares for initialization by turning on species that have requested initialization and turning off + species that have not requested initialization. This function should be accompanied by a call to + _endInitialization. */ +static void _beginInitialization(void){ + int i, j; /* For iterating over cells */ + SppIndex sp; /* For iterating over species */ + Bool temporary_storage; /* For swapping variables */ + + DuringInitialization = TRUE; + + /* Swap Species[sp]->use_me and mySpeciesInit.shouldBeInitialized[sp]. shouldBeInitialized is an array + of booleans that represent whether the given species should be used in initialization. use_me is a + boolean that represents whether the given species should be used in production. By swaping them we + save space, but we have to remember to swap them back before the production run. */ + for(i = 0; i < grid_Rows; ++i){ + for(j = 0; j < grid_Cols; ++j){ + if(!gridCells[i][j].mySpeciesInit.useInitialization){ + continue; + } + load_cell(i, j); /* We could do this without loading the cell, but there would be no guarantee + that ForEachGroup would iterate correctly */ + + /* Begin swaping variables */ + ForEachSpecies(sp){ + // Temporarily store use_me + temporary_storage = Species[sp]->use_me; + // Swap use_me + Species[sp]->use_me = gridCells[i][j].mySpeciesInit.shouldBeInitialized[sp]; + // Swap shouldBeInitialized[sp] + gridCells[i][j].mySpeciesInit.shouldBeInitialized[sp] = temporary_storage; + } /* End for each species */ + } /* End for each column */ + } /* End for each row */ + unload_cell(); // Reset the global variables +} + +/* Return the program to the state it needs to be in for the main simulation. This should only be called if you + have called _beginInitialization. */ +static void _endInitialization(void){ + // Calling this function a second time will swap the variables back to their original state. + _beginInitialization(); + // Save the state of the program as our initialization conditions. + _saveAsInitializationConditions(); + // We have now exited initialization. + DuringInitialization = FALSE; +} + +/* Save the current state of the program as spinup conditions. + * + * This is low level function. If you have already called + * _endInitialization() there is no need to call this function. */ +static void _saveAsInitializationConditions(){ + // Save gridCells as initializationCells + initializationCells = gridCells; + // Nullify gridCells. This ensures we can no longer modify initializationCells on accident. + gridCells = NULL; + + // The easiest way to reallocate gridCells is reread the files. + rereadInputs(); +} + +/* Load the state of the program right after initialization. */ +void loadInitializationConditions(){ + int row, col; + GrpIndex rg; + SppIndex sp; + + for(row = 0; row < grid_Rows; ++row){ + for(col = 0; col < grid_Cols; ++col){ + load_cell(row, col); + + ForEachSpecies(sp){ + copy_species(initializationCells[row][col].mySpecies[sp], Species[sp]); + } + + ForEachGroup(rg){ + copy_rgroup(initializationCells[row][col].myGroup[rg], RGroup[rg]); + } + + copy_environment(&initializationCells[row][col].myEnvironment, Env); + copy_plot(&initializationCells[row][col].myPlot, Plot); + copy_succulent(&initializationCells[row][col].mySucculent, Succulent); + + unload_cell(); + } + } + +} + +/* "Spinup" the model by running without stat collection, fire, or grazing. + * + * Fire and grazing will potentially be added to spinup as a future feature. */ +static void _run_spinup(void) +{ + Bool killedany; // killedany for mortality functions + + rgroup_Establish(); // Establish individuals. Excludes annuals. + Env_Generate(); // Generated the SOILWAT environment + rgroup_PartResources(); // Distribute resources + rgroup_Grow(); // Grow + mort_Main(&killedany); // Mortality that occurs during the growing season + rgroup_IncrAges(); // Increment ages of all plants + _kill_annuals(); // Kill annuals + _kill_maxage(); // Kill plants that reach max age + _kill_extra_growth(); // Kill superfluous growth +} + +/* TODO: This is a dummy method. It needs to be implemented once seed dispersal is fully planned. + * + * Note on implementing: The logic behind calling this function already exists. You can view the + * function call inside runInitialization, but the important thing to note is that this + * function is called inside the following structure: + * + * for each year + * for each grid cell + * _run_seed_initialization + * + * You can assume that prior to this function being called the correct grid cell has been loaded + * into the global variables (RGroup, Species, Env, ect.) and that this function must + * operate on a yearly time step. */ +static void _run_seed_initialization(void){ + if(Globals->currYear == 1){ + printf("\nYou have attempted to initialize with seed dispersal.\n" + "This option is currently in development and will be availible soon.\n"); + } + initializationMethod = INIT_WITH_NOTHING; + return; +} + +/* Free memory allocated to initializationCells. This function should only be called once per simulation. */ +void freeInitializationMemory(void) +{ + // Remember where gridCells pointed. + CellType** locationOfGridCells = gridCells; + + // If initializationCells is allocated. + if(initializationCells){ + // move gridCells to point to initializationCells. This allows us to deallocate using free_grid_memory(); + gridCells = initializationCells; + // Since we already have a function to deallocate gridCells we can use it. + free_grid_memory(); + // And we need to reset gridCells in case it hasn't been deallocated. + gridCells = locationOfGridCells; + } +} \ No newline at end of file diff --git a/ST_initialization.h b/ST_initialization.h new file mode 100644 index 00000000..8b7ede62 --- /dev/null +++ b/ST_initialization.h @@ -0,0 +1,41 @@ +/***********************************************************************/ +/* ST_initialization.h + This header defines the functions exported from ST_initialization.c. + Initialization is currently only availible when running gridded + mode. + + Initial programming by Chandler Haukap in August of 2019. */ +/***********************************************************************/ + +#ifndef INITIALIZATION_H +#define INITIALIZATION_H + +/* This module only functions in the context of gridded mode. */ +#include"ST_grid.h" + +/**************** Enumerator for initialization types ******************/ + +/* Possible methods of initialization. */ +typedef enum +{ + INIT_WITH_SPINUP, + INIT_WITH_SEEDS, + INIT_WITH_NOTHING +} InitializationMethod; + +/********** Exported functions defined in ST_initialization.c ***********/ + +void runInitialization(void); +void loadInitializationConditions(void); +void freeInitializationMemory(void); + +/************************ Exported variables ****************************/ + +/* Stores the state of the cells following spinup. */ +CellType** initializationCells; +/* The method of initialization specified in inputs. */ +InitializationMethod initializationMethod; +/* TRUE if the program is currently in initialization. */ +Bool DuringInitialization; + +#endif \ No newline at end of file diff --git a/ST_main.c b/ST_main.c index 4ec93801..16099287 100644 --- a/ST_main.c +++ b/ST_main.c @@ -33,13 +33,17 @@ #include "sw_src/SW_Output_outtext.h" #include "sw_src/SW_Output_outarray.h" #include "sw_src/rands.h" -extern SXW_t SXW; +#include "ST_stats.h" +#include "ST_initialization.h" +#include "ST_progressBar.h" +#include "ST_seedDispersal.h" extern Bool prepare_IterationSummary; // defined in `SOILWAT2/SW_Output.c` extern Bool print_IterationSummary; // defined in `SOILWAT2/SW_Output_outtext.c` extern Bool storeAllIterations; // defined in `SOILWAT2/SW_Output.c` extern SW_VEGPROD SW_VegProd; SW_FILE_STATUS SW_File_Status; +extern Bool* _SomeKillage; /************* External Function Declarations **************/ /***********************************************************/ @@ -60,20 +64,14 @@ SW_FILE_STATUS SW_File_Status; void output_Bmass_Yearly( Int year ); void output_Mort_Yearly( void ); - void stat_Collect( Int year ) ; - void stat_Collect_GMort ( void ) ; - void stat_Collect_SMort ( void ) ; - - void stat_Output_AllMorts( void) ; - void stat_Output_AllBmass(void) ; - - /* void runGrid( void ); //for the grid... declared in ST_grid.c */ - void _kill_annuals(void); void _kill_extra_growth(void); void _kill_maxage(void); void save_annual_species_relsize(void); + void files_init(void); + void maxrgroupspecies_init(void); + #ifdef DEBUG_MEM #define chkmem_f CheckMemoryIntegrity(FALSE); #define chkmem_t CheckMemoryIntegrity(TRUE); @@ -87,6 +85,8 @@ SW_FILE_STATUS SW_File_Status; /*************** Local Function Declarations ***************/ /***********************************************************/ void Plot_Initialize( void); +void allocate_Globals(void); +void deallocate_Globals(Bool isGriddedMode); static void usage(void) { char *s ="STEPPE plant community dynamics (SGS-LTER Jan-04).\n" @@ -121,16 +121,15 @@ FILE *logfp, /* used everywhere by LogError */ int logged; /* indicator that err file was written to */ SpeciesType **Species; GroupType **RGroup; -SucculentType Succulent; -EnvType Env; -PlotType Plot; -ModelType Globals; +SucculentType *Succulent; +EnvType *Env; +PlotType *Plot; +ModelType *Globals; +GlobalType SuperGlobals; BmassFlagsType BmassFlags; MortFlagsType MortFlags; Bool UseGrid; -Bool UseSeedDispersal; -Bool DuringSpinup; Bool EchoInits; Bool UseProgressBar; Bool STdebug_requested; @@ -148,7 +147,7 @@ extern pcg32_random_t markov_rng; /******************** Begin Model Code *********************/ /***********************************************************/ int main(int argc, char **argv) { - IntS year, iter, incr; + IntS year, iter; Bool killedany; logged = FALSE; @@ -164,12 +163,16 @@ int main(int argc, char **argv) { printf("STEPWAT init_args() executed successfully \n"); - /* - if (UseGrid == TRUE) { + if (UseGrid) { runGrid(); return 0; } - */ + + /* Read files.in and maxrgroupspecies.in before everything else */ + files_init(); + maxrgroupspecies_init(); + + allocate_Globals(); parm_Initialize(); @@ -187,43 +190,36 @@ int main(int argc, char **argv) { ST_connect("Output/stdebug"); } - incr = (IntS) ((float) Globals.runModelIterations / 10); - if (incr == 0) - incr = 1; - /* --- Begin a new iteration ------ */ - for (iter = 1; iter <= Globals.runModelIterations; iter++) { - if (progfp == stderr) { - if (iter % incr == 0) - fprintf(progfp, "."); - } else { - fprintf(progfp, "%d\n", iter); - } - + for (iter = 1; iter <= SuperGlobals.runModelIterations; iter++) { Plot_Initialize(); - RandSeed(Globals.randseed, &environs_rng); - RandSeed(Globals.randseed, &mortality_rng); - RandSeed(Globals.randseed, &resgroups_rng); - RandSeed(Globals.randseed, &species_rng); - RandSeed(Globals.randseed, &grid_rng); - RandSeed(Globals.randseed, &markov_rng); - - Globals.currIter = iter; + + RandSeed(SuperGlobals.randseed, &environs_rng); + RandSeed(SuperGlobals.randseed, &mortality_rng); + RandSeed(SuperGlobals.randseed, &resgroups_rng); + RandSeed(SuperGlobals.randseed, &species_rng); + RandSeed(SuperGlobals.randseed, &grid_rng); + RandSeed(SuperGlobals.randseed, &markov_rng); + + Globals->currIter = iter; if (storeAllIterations) { - SW_OUT_create_iteration_files(Globals.currIter); + SW_OUT_create_iteration_files(Globals->currIter); } if (prepare_IterationSummary) { - print_IterationSummary = (Bool) (Globals.currIter == Globals.runModelIterations); + print_IterationSummary = (Bool) (Globals->currIter == SuperGlobals.runModelIterations); } /* ------ Begin running the model ------ */ - for (year = 1; year <= Globals.runModelYears; year++) { + for (year = 1; year <= SuperGlobals.runModelYears; year++) { + if(UseProgressBar){ + logProgress(iter, year, SIMULATION); + } - //printf("------------------------Repetition/year = %d / %d\n", iter, year); + //printf("------------------------Repetition/year = %d / %d\n", iter, year); - Globals.currYear = year; + Globals->currYear = year; rgroup_Establish(); @@ -231,7 +227,7 @@ int main(int argc, char **argv) { rgroup_PartResources(); - if (!isnull(SXW.debugfile) ) SXW_PrintDebug(0); + if (!isnull(SXW->debugfile) ) SXW_PrintDebug(0); rgroup_Grow(); @@ -289,14 +285,18 @@ int main(int argc, char **argv) { // dont need to restart if last iteration finished // this keeps it from re-writing the output folder and overwriting output files - if (Globals.currIter != Globals.runModelIterations) + if (Globals->currIter != SuperGlobals.runModelIterations) { // don't reset in last iteration because we need to close files // before clearing/de-allocated SOILWAT2-memory - SXW_Reset(); + SXW_Reset(SXW->f_watin); } } /* end model run for this iteration*/ + if(UseProgressBar){ + logProgress(0, 0, OUTPUT); + } + /*------------------------------------------------------*/ if (MortFlags.summary) stat_Output_AllMorts(); @@ -308,7 +308,7 @@ int main(int argc, char **argv) { ST_disconnect(); } - if (!isnull(SXW.debugfile)){ + if (!isnull(SXW->debugfile)){ printf("entering debugfile\n"); SXW_PrintDebug(1); } @@ -317,8 +317,11 @@ int main(int argc, char **argv) { SW_CTL_clear_model(TRUE); // de-allocate all memory free_all_sxw_memory(); - printf("\nend program\n"); - fprintf(progfp, "\n"); + deallocate_Globals(FALSE); + + // This isn't wrapped in an if statement on purpose. + // We should print "Done" either way. + logProgress(0, 0, DONE); return 0; } @@ -400,6 +403,60 @@ void Plot_Initialize(void) { SXW_InitPlot(); } +/* Allocates memory for any global variables defined as pointers */ +void allocate_Globals(void){ + Env = (EnvType*) Mem_Calloc(1, sizeof(EnvType), "allocate_Globals: Env"); + Succulent = (SucculentType*) Mem_Calloc(1, sizeof(SucculentType), "allocate_Globals: Succulent"); + Globals = (ModelType*) Mem_Calloc(1, sizeof(ModelType), "allocate_Globals: Globals"); + Plot = (PlotType*) Mem_Calloc(1, sizeof(PlotType), "allocate_Globals: Plot"); + _SomeKillage = (Bool*) Mem_Calloc(1, sizeof(Bool), "allocate_Globals: _SomeKillage"); +} + +/* Deallocates the global variables */ +void deallocate_Globals(Bool isGriddedMode){ + GrpIndex rg; + SppIndex sp; + + if(!isGriddedMode){ + Mem_Free(Env); + Mem_Free(Succulent); + Mem_Free(Globals); + Mem_Free(Plot); + Mem_Free(_SomeKillage); + } + + /* Free Species */ + ForEachSpecies(sp){ + /* Start by freeing any pointers in the Species struct */ + Mem_Free(Species[sp]->kills); + Mem_Free(Species[sp]->seedprod); + Mem_Free(Species[sp]->name); + IndivType *indv = Species[sp]->IndvHead, *next; + /* Next free the linked list of individuals */ + while(indv){ + next = indv->Next; + Mem_Free(indv); + indv = next; + } + Mem_Free(indv); + /* Finally free the actual species */ + Mem_Free(Species[sp]); + } + /* Then free the entire array */ + Mem_Free(Species); + + /* Free RGroup */ + ForEachGroup(rg){ + /* Free all pointers in the RGroup struct */ + Mem_Free(RGroup[rg]->est_spp); + Mem_Free(RGroup[rg]->kills); + Mem_Free(RGroup[rg]->name); + Mem_Free(RGroup[rg]->species); + Mem_Free(RGroup[rg]); + } + /* Then free the entire array */ + Mem_Free(RGroup); +} /**************************************************************/ static void init_args(int argc, char **argv) { @@ -440,7 +497,6 @@ static void init_args(int argc, char **argv) { /* Defaults */ parm_SetFirstName( DFLT_FIRSTFILE); QuietMode = EchoInits = UseSeedDispersal = FALSE; - SXW.debugfile = NULL; progfp = stderr; @@ -549,7 +605,7 @@ static void init_args(int argc, char **argv) { case 8: // -s if (strlen(argv[a]) > 1){ printf("Generating SXW debug file\n"); - SXW.debugfile = Str_Dup(&argv[a][1]); + SXW->debugfile = Str_Dup(&argv[a][1]); } break; @@ -615,7 +671,7 @@ void check_sizes(const char *chkpt) { if (LT(diff, fabs(spsize - getSpeciesRelsize(sp)))) { LogError(stdout, LOGWARN, "%s (%d:%d): SP: \"%s\" size error: " "SP=%.7f, ndv=%.7f", - chkpt, Globals.currIter, Globals.currYear, + chkpt, Globals->currIter, Globals->currYear, Species[sp]->name, getSpeciesRelsize(sp), spsize); } } @@ -623,7 +679,7 @@ void check_sizes(const char *chkpt) { if (LT(diff, fabs(rgsize - getRGroupRelsize(rg)))) { LogError(stdout, LOGWARN, "%s (%d:%d): RG \"%s\" size error: " "RG=%.7f, ndv=%.7f", - chkpt, Globals.currIter, Globals.currYear, + chkpt, Globals->currIter, Globals->currYear, RGroup[rg]->name, getRGroupRelsize(rg), rgsize); } } diff --git a/ST_mortality.c b/ST_mortality.c index 5b22f092..5916526e 100644 --- a/ST_mortality.c +++ b/ST_mortality.c @@ -68,7 +68,7 @@ void _kill_maxage(void); /************ File-Level Variable Declarations *************/ /***********************************************************/ -Bool _SomeKillage; +Bool *_SomeKillage; /* flag: some plant was reduced and PR is affected. */ /* 7/5/01 - currently flag is set but unused. */ extern @@ -138,7 +138,7 @@ void mort_Main( Bool *killed) { SppIndex sp; GroupType *g; - _SomeKillage = FALSE; + *_SomeKillage = FALSE; ForEachGroup(rg) { g = RGroup[rg]; @@ -172,14 +172,14 @@ void mort_Main( Bool *killed) { } /* Implement mortality of succulents if this year's PPT is above the PPT threshold that triggers succulent mortality */ if (g->succulent - && Env.wet_dry == Ppt_Wet - && RandUni(&mortality_rng) <= Succulent.prob_death ) + && Env->wet_dry == Ppt_Wet + && RandUni(&mortality_rng) <= Succulent->prob_death ) _succulents( sp ); /* Finally, implement mortality due to fecal pats, ant mounds, or animal burrows * (disturbances originally conceptualized for the shortgrass steppe that result in * plant mortality */ - switch (Plot.disturbance) { + switch (Plot->disturbance) { case FecalPat: _pat( sp); break; @@ -201,7 +201,7 @@ void mort_Main( Bool *killed) { } /* end ForEachGroup(rg) */ - *killed = _SomeKillage; + killed = _SomeKillage; } /***********************************************************/ @@ -223,7 +223,7 @@ void mort_EndOfYear(void) { /* Check species index number from the beginning to all the species in * species.in , if the species name == checkname then get the biomass and stop the loop*/ - for (i = 0; i < Globals.sppCount; i++) { /* if species name = checkname = brte then get the biomass of brte(cheatgrass)*/ + for (i = 0; i < Globals->sppCount; i++) { /* if species name = checkname = brte then get the biomass of brte(cheatgrass)*/ if (strcmp(cheatgrass_name, Species[i]->name) == 0) { biomass_cheatgrass = Species_GetBiomass(i); /* calculate biomass of cheatgrass*/ g = RGroup[Species[i]->res_grp]; @@ -245,7 +245,7 @@ void mort_EndOfYear(void) { // in this for loop "g" refers to the RGroup of cheatgrass. RGroup[rg] refers // to the current iteration's RGroup. ForEachGroup(rg) { - if (Globals.currYear < RGroup[rg]->startyr) { + if (Globals->currYear < RGroup[rg]->startyr) { continue; } @@ -275,27 +275,27 @@ void mort_EndOfYear(void) { // If a wildfire occurs this year if (random_number <= fire_possibility) { - RGroup[rg]->killyr = Globals.currYear; + RGroup[rg]->killyr = Globals->currYear; /* Increase the number of wildfires that have occurred across all iterations in this year by 1 */ RGroup[rg]->wildfire = 1; } /* ------------------------- END WILDFIRE BASED ON CHEATGRASS BIOMASS ------------------------- */ - } else if(Globals.currYear >= RGroup[rg]->killfreq_startyr) { // Otherwise simulate prescribed fire + } else if(Globals->currYear >= RGroup[rg]->killfreq_startyr) { // Otherwise simulate prescribed fire if(RGroup[rg]->killfreq < 1){ /* --------------------- STOCHASTIC PRESCRIBED FIRE -------------------- */ if(random_number <= RGroup[rg]->killfreq) { - RGroup[rg]->killyr = Globals.currYear; + RGroup[rg]->killyr = Globals->currYear; /* Increase the number of prescribed fires that have occurred across all iterations in this year by 1 */ RGroup[rg]->prescribedfire = 1; } /* ------------------- END STOCHASTIC PRESCRIBED FIRE ----------------- */ - } else if (((Globals.currYear - RGroup[rg]->killfreq_startyr) % (IntU) RGroup[rg]->killfreq) == 0) { + } else if (((Globals->currYear - RGroup[rg]->killfreq_startyr) % (IntU) RGroup[rg]->killfreq) == 0) { /* ------------------------ PRESCRIBED FIRE AT A FIXED RETURN INTERVAL ----------------------- */ - RGroup[rg]->killyr = Globals.currYear; + RGroup[rg]->killyr = Globals->currYear; /* Calculate the prescribed fire counts */ RGroup[rg]->prescribedfire = 1; /* ------------------------ END PRESCRIBED FIRE AT A FIXED RETURN INTERVAL ------------------- */ @@ -303,18 +303,18 @@ void mort_EndOfYear(void) { } /* Kill all individuals of the functional group and don't let them re-establish */ - if (Globals.currYear == RGroup[rg]->extirp) { + if (Globals->currYear == RGroup[rg]->extirp) { rgroup_Extirpate(rg); /* If the current year is a kill year, implement mortality */ - } else if (Globals.currYear == RGroup[rg]->killyr) { + } else if (Globals->currYear == RGroup[rg]->killyr) { RGroup_Kill(rg); } /* If the current year is a fire year, then remove extra_growth here instead of in _kill_extra_growth called in ST_main.c. Otherwise, biomass will be non-zero in a fire year with complete killing */ - if (Globals.currYear == RGroup[rg]->killyr) { + if (Globals->currYear == RGroup[rg]->killyr) { if (!RGroup[rg]->use_extra_res){ continue; } @@ -348,35 +348,32 @@ void grazing_EndOfYear( void){ IntU grazingyr =0; g = RGroup[rg]; - //printf("inside grazing_EndOfYear() year=%d, rgroupName=%s, grazingfreq_startyr=%d, grazingfreq=%d, proportionGrazing=%f startYear=%d \n",Globals.currYear,g->name,g->grazingfreq_startyr,g->grazingfrq,g->proportion_grazing, RGroup[rg]->startyr); - - if (Globals.currYear < RGroup[rg]->startyr) + if (Globals->currYear < RGroup[rg]->startyr) { /* Grazing cannot occur for an RGroup[rg] until the year that RGroup[rg] is turned on */ continue; } - if ((Globals.currYear >=g->grazingfreq_startyr) && (g->grazingfrq > 0)) + if ((Globals->currYear >=g->grazingfreq_startyr) && (g->grazingfrq > 0)) { if (g->grazingfrq < 1.0) { if (RandUni(&mortality_rng) <= g->grazingfrq) { - grazingyr = Globals.currYear; + grazingyr = Globals->currYear; } } - else if (((Globals.currYear - g->grazingfreq_startyr) % (IntU) g->grazingfrq) == 0) + else if (((Globals->currYear - g->grazingfreq_startyr) % (IntU) g->grazingfrq) == 0) { - grazingyr = Globals.currYear; + grazingyr = Globals->currYear; } } //Implement grazing if this year is a year where grazing should occur - if (Globals.currYear == grazingyr) + if (Globals->currYear == grazingyr) { - //printf( "currYear is equal to grazingYear so will iterate all the Species for doing grazing, RGroup[g]->est_count =%d \n",RGroup[rg]->est_count); Int i; ForEachEstSpp2( rg, i) { @@ -384,8 +381,7 @@ void grazing_EndOfYear( void){ { continue; } - //printf( "year=%d calling Species_Proportion_Grazing() rgroupName=%s, est_count =%d,grazingfreq_startyr=%d, grazingfreq=%d, proportionGrazing=%f \n",Globals.currYear,g->name,RGroup[rg]->est_count,g->grazingfreq_startyr,g->grazingfrq,g->proportion_grazing); - + /* Remove plant biomass to implement grazing using the proportion_grazing specified in inputs */ Species_Proportion_Grazing(RGroup[rg]->est_spp[i],RGroup[rg]->proportion_grazing ); } @@ -408,14 +404,14 @@ void proportion_Recovery(void) { ForEachGroup(rg) { - if (Globals.currYear < RGroup[rg]->startyr) { + if (Globals->currYear < RGroup[rg]->startyr) { /* Recovery of biomass after fire cannot occur for an RGroup[rg] until the year * that RGroup[rg] is turned on */ continue; } // Implement recovery of biomass after fire that represents re-sprouting - if (Globals.currYear == RGroup[rg]->killyr) { + if (Globals->currYear == RGroup[rg]->killyr) { Int i; //printf("'before proportion_recovery': Group = %s, relsize = %f, est_count = %d\n", @@ -454,12 +450,12 @@ static void _pat( const SppIndex sp) { Int i, k=-1; IndivType *p, **kills; - kills = (IndivType **)Mem_Calloc(Globals.max_indivs_per_spp, sizeof(IndivType *), "_pat"); + kills = (IndivType **)Mem_Calloc(SuperGlobals.max_indivs_per_spp, sizeof(IndivType *), "_pat"); /* ---------------------------------------------*/ /* Generate kill list, depending on sensitivity */ /* ---------------------------------------------*/ - if ( Plot.pat_removed) { + if ( Plot->pat_removed) { /* get list of seedlings and annuals*/ ForEachIndiv(p, Species[sp]) { if ( p->age == 1 || Species[sp]->disturbclass == VerySensitive) @@ -483,7 +479,7 @@ static void _pat( const SppIndex sp) { } } - if (k >= 0) _SomeKillage = TRUE; + if (k >= 0) *_SomeKillage = TRUE; Mem_Free(kills); } @@ -516,7 +512,7 @@ static void _mound( const SppIndex sp) { } - if (k) _SomeKillage = TRUE; + if (k) *_SomeKillage = TRUE; } @@ -542,7 +538,7 @@ static void _burrow( const SppIndex sp) { k = TRUE; } - if (k ) _SomeKillage = TRUE; + if (k ) *_SomeKillage = TRUE; } @@ -566,10 +562,10 @@ static void _succulents( const SppIndex sp) { IndivType *p, **kills; - RealF killamt = Succulent.reduction; + RealF killamt = Succulent->reduction; int i, k=0; - kills = (IndivType **)Mem_Calloc(Globals.max_indivs_per_spp, sizeof(IndivType *), "_succulents"); + kills = (IndivType **)Mem_Calloc(SuperGlobals.max_indivs_per_spp, sizeof(IndivType *), "_succulents"); ForEachIndiv (p, Species[sp]) { if ( GT(p->relsize, killamt) ) @@ -582,7 +578,7 @@ static void _succulents( const SppIndex sp) { indiv_Kill_Complete(kills[i], 7); - if (Species[sp]->est_count) _SomeKillage = TRUE; + if (Species[sp]->est_count) *_SomeKillage = TRUE; Mem_Free(kills); } @@ -617,7 +613,7 @@ static void _slow_growth( const SppIndex sp) { IndivType *ndv, **kills; - kills = (IndivType **)Mem_Calloc(Globals.max_indivs_per_spp, sizeof(IndivType *), "_slow_growth"); + kills = (IndivType **)Mem_Calloc(SuperGlobals.max_indivs_per_spp, sizeof(IndivType *), "_slow_growth"); slowrate = RGroup[Species[sp]->res_grp]->slowrate * Species[sp]->max_rate; @@ -638,7 +634,7 @@ static void _slow_growth( const SppIndex sp) { for( n=0; n <= k; n++ ) indiv_Kill_Complete(kills[n], 8); - if (k >= 0) _SomeKillage = TRUE; + if (k >= 0) *_SomeKillage = TRUE; Mem_Free(kills); } @@ -686,7 +682,7 @@ static void _age_independent( const SppIndex sp) { indiv_Kill_Complete(kills[n], 9); } - if (k >= 0) _SomeKillage = TRUE; + if (k >= 0) *_SomeKillage = TRUE; Mem_Free(kills); @@ -735,7 +731,7 @@ static void _no_resources( GrpIndex rg) { for( i=0; i < nk; i++) indiv_Kill_Complete(indv_list[i], 10); - if (nk) _SomeKillage = TRUE; + if (nk) *_SomeKillage = TRUE; /* Check to see if this group's resources have been stretched, * and commit mortality of clonal plants which get additional @@ -774,7 +770,7 @@ static void _stretched_clonal( GrpIndex rg, Int start, Int last, IndivType **clist; /* list of clonal individuals */ - clist = (IndivType **)Mem_Calloc(Globals.max_indivs_per_spp, sizeof(IndivType *), "_stretched_clonal"); + clist = (IndivType **)Mem_Calloc(SuperGlobals.max_indivs_per_spp, sizeof(IndivType *), "_stretched_clonal"); /* get a list of remaining clonal plants, still ranked by size */ for( np=-1, i=start; i <= last; i++) { @@ -803,7 +799,7 @@ static void _stretched_clonal( GrpIndex rg, Int start, Int last, indiv_Kill_Complete(clist[i], 11); } - if (nk >= 0) _SomeKillage = TRUE; + if (nk >= 0) *_SomeKillage = TRUE; } else { /* reduce inverse-proportionally */ @@ -835,7 +831,7 @@ static void _stretched_clonal( GrpIndex rg, Int start, Int last, indiv_reduction); } - if (np >= 0) _SomeKillage = TRUE; + if (np >= 0) *_SomeKillage = TRUE; } /* end if pm*/ } /* end if y >= 1*/ diff --git a/ST_output.c b/ST_output.c index 18281bbb..8a6f18ff 100644 --- a/ST_output.c +++ b/ST_output.c @@ -60,7 +60,7 @@ void output_Bmass_Yearly( Int year ) { fields[i] = (char *)Mem_Calloc(MAX_FIELDLEN + 1, sizeof(char), "output_Bmass_Yearly"); } - if(Globals.currYear == 1) // At year one we need a header. + if(Globals->currYear == 1) // At year one we need a header. { /* --------- Begin setting up header ------- */ @@ -107,18 +107,18 @@ void output_Bmass_Yearly( Int year ) { } } sprintf(filename, "%s%0*d.csv", Parm_name(F_BMassPre), - Globals.bmass.suffixwidth, - Globals.currIter); - Globals.bmass.fp_year = OpenFile(filename, "a"); + Globals->bmass.suffixwidth, + Globals->currIter); + Globals->bmass.fp_year = OpenFile(filename, "a"); /* Write data line to already opened file */ for (i=0; i< fc-1; i++) { - fprintf(Globals.bmass.fp_year,"%s%c", fields[i], BmassFlags.sep); + fprintf(Globals->bmass.fp_year,"%s%c", fields[i], BmassFlags.sep); } - if (i) fprintf(Globals.bmass.fp_year,"%s\n", fields[i]); - fflush(Globals.bmass.fp_year); - CloseFile(&Globals.bmass.fp_year); + if (i) fprintf(Globals->bmass.fp_year,"%s\n", fields[i]); + fflush(Globals->bmass.fp_year); + CloseFile(&Globals->bmass.fp_year); fc = 0; //reset fc for first line of data. } @@ -129,7 +129,7 @@ void output_Bmass_Yearly( Int year ) { } if (BmassFlags.dist) { - switch (Plot.disturbance) { + switch (Plot->disturbance) { case NoDisturb: strcpy(s, "None"); break; case FecalPat: strcpy(s, "Pat"); break; case AntMound: strcpy(s, "Mound"); break; @@ -140,10 +140,10 @@ void output_Bmass_Yearly( Int year ) { } if (BmassFlags.ppt) - sprintf(fields[fc++], "%d", Env.ppt); + sprintf(fields[fc++], "%d", Env->ppt); if (BmassFlags.pclass) { - switch (Env.wet_dry) { + switch (Env->wet_dry) { case Ppt_Norm: strcpy(s, "Normal"); break; case Ppt_Wet: strcpy(s, "Wet"); break; case Ppt_Dry: strcpy(s, "Dry"); break; @@ -153,7 +153,7 @@ void output_Bmass_Yearly( Int year ) { } if (BmassFlags.tmp) - sprintf(fields[fc++], "%0.1f", Env.temp); + sprintf(fields[fc++], "%0.1f", Env->temp); if (BmassFlags.grpb) { if (BmassFlags.wildfire) @@ -177,18 +177,18 @@ void output_Bmass_Yearly( Int year ) { } } sprintf(filename, "%s%0*d.csv", Parm_name(F_BMassPre), - Globals.bmass.suffixwidth, - Globals.currIter); - Globals.bmass.fp_year = OpenFile(filename, "a"); + Globals->bmass.suffixwidth, + Globals->currIter); + Globals->bmass.fp_year = OpenFile(filename, "a"); /* Write data line to already opened file */ for (i=0; i< fc-1; i++) { - fprintf(Globals.bmass.fp_year,"%s%c", fields[i], BmassFlags.sep); + fprintf(Globals->bmass.fp_year,"%s%c", fields[i], BmassFlags.sep); } - if (i) fprintf(Globals.bmass.fp_year,"%s\n", fields[i]); - fflush(Globals.bmass.fp_year); - CloseFile(&Globals.bmass.fp_year); + if (i) fprintf(Globals->bmass.fp_year,"%s\n", fields[i]); + fflush(Globals->bmass.fp_year); + CloseFile(&Globals->bmass.fp_year); for (i = 0; i < MAX_OUTFIELDS; i++) { Mem_Free(fields[i]); @@ -206,9 +206,9 @@ void output_Mort_Yearly( void ) { IntS age, rg, sp; char filename[FILENAME_MAX]; - sprintf(filename, "%s%0*d.csv", Parm_name(F_MortPre), Globals.mort.suffixwidth, Globals.currIter); - Globals.mort.fp_year = OpenFile(filename, "a"); - FILE *f = Globals.mort.fp_year; + sprintf(filename, "%s%0*d.csv", Parm_name(F_MortPre), Globals->mort.suffixwidth, Globals->currIter); + Globals->mort.fp_year = OpenFile(filename, "a"); + FILE *f = Globals->mort.fp_year; if (!MortFlags.yearly) return; @@ -231,7 +231,7 @@ void output_Mort_Yearly( void ) { fprintf(f, "(Estabs)"); if (MortFlags.group) { ForEachGroup(rg) - fprintf(Globals.mort.fp_year, "%c%d", MortFlags.sep, RGroup[rg]->estabs); + fprintf(Globals->mort.fp_year, "%c%d", MortFlags.sep, RGroup[rg]->estabs); } if (MortFlags.species) { ForEachSpecies(sp) @@ -241,7 +241,7 @@ void output_Mort_Yearly( void ) { /* now print the kill data */ - for (age = 0; age < Globals.Max_Age; age++) { + for (age = 0; age < Globals->Max_Age; age++) { fprintf(f, "%d", age + 1); if (MortFlags.group) { ForEachGroup(rg) @@ -268,5 +268,5 @@ void output_Mort_Yearly( void ) { fprintf(f, "\n"); } - CloseFile(&Globals.mort.fp_year); + CloseFile(&Globals->mort.fp_year); } diff --git a/ST_params.c b/ST_params.c index 38363504..b531565e 100644 --- a/ST_params.c +++ b/ST_params.c @@ -48,17 +48,16 @@ SppIndex species_New(void); void parm_SetFirstName( char *s); void parm_SetName( char *s, int which); void parm_free_memory( void ); + void maxrgroupspecies_init(void); + void files_init(void); /*********** Locally Used Function Declarations ************/ /***********************************************************/ -static void _globals_init( void); static void _env_init( void); static void _plot_init( void); static void _setNameLen(char *dest, char *src, Int len); -static void _maxrgroupspecies_init( void); static void _rgroup_init( void); static void _species_init( void); -static void _files_init( void ); static void _check_species( void); static void _bmassflags_init( void); static void _mortflags_init( void); @@ -95,14 +94,11 @@ char *MyFileName; /**************************************************************/ void parm_Initialize() { /*======================================================*/ - _globals_init(); - _files_init(); _model_init(); _env_init(); _plot_init(); _bmassflags_init(); _mortflags_init(); - _maxrgroupspecies_init(); _rgroup_init(); _species_init(); _check_species(); @@ -136,21 +132,8 @@ void parm_SetName( char *s, int which) { } - /**************************************************************/ -static void _globals_init( void) { -/*======================================================*/ -/* this memset() goes against the mymemory model, but I'm not - * sure of the best approach to take for static vars */ - memset ( &Globals, 0, sizeof(struct globals_st)); - /*Globals.outf = NULL; */ - - - -} - -/**************************************************************/ -static void _files_init( void ) { +void files_init( void ) { /*======================================================*/ /* 7-May-02 (cwb) added code to interface with SOILWAT */ @@ -187,34 +170,33 @@ static void _files_init( void ) { /**************************************************************/ static void _model_init( void) { /*======================================================*/ - FILE *f; - int seed; + int seed, years; char tmp[80]; MyFileName = Parm_name(F_Model); f = OpenFile(MyFileName, "r"); - /* ----------------------------------------------------*/ /* scan for the first line*/ if (!GetALine(f, inbuf)) { LogError(logfp, LOGFATAL, "%s: No data found!\n", MyFileName); } else { - sscanf( inbuf, "%s %hu %d", + sscanf( inbuf, "%s %d %d", tmp, - &Globals.runModelYears, + &years, &seed); - Globals.Max_Age = Globals.runModelYears; - Globals.runModelIterations = atoi(tmp); - if (Globals.runModelIterations < 1 || - Globals.runModelYears < 1 ) { + SuperGlobals.runModelYears = years; + Globals->Max_Age = SuperGlobals.runModelYears; + SuperGlobals.runModelIterations = atoi(tmp); + if (SuperGlobals.runModelIterations < 1 || + SuperGlobals.runModelYears < 1 ) { LogError(logfp, LOGFATAL,"Invalid parameters for RunModelIterations " "or RunModelYears (%s)", MyFileName); } - Globals.bmass.suffixwidth = Globals.mort.suffixwidth = strlen(tmp); - Globals.randseed = (IntL) ((seed) ? -abs(seed) : 0); + Globals->bmass.suffixwidth = Globals->mort.suffixwidth = strlen(tmp); + SuperGlobals.randseed = (IntL) ((seed) ? -abs(seed) : 0); } CloseFile(&f); @@ -242,47 +224,47 @@ static void _env_init( void) { switch(++index) { case 1: x=sscanf( inbuf, "%f %f %hu %hu %hu %hu %f %hu", - &Globals.ppt.avg, &Globals.ppt.std, - &Globals.ppt.min, &Globals.ppt.max, - &Globals.ppt.dry, &Globals.ppt.wet, - &Globals.gsppt_prop, &Globals.transp_window); + &Globals->ppt.avg, &Globals->ppt.std, + &Globals->ppt.min, &Globals->ppt.max, + &Globals->ppt.dry, &Globals->ppt.wet, + &Globals->gsppt_prop, &Globals->transp_window); nitems = 8; break; case 2: x=sscanf( inbuf, "%f %f %f %f %f", - &Globals.temp.avg, &Globals.temp.std, - &Globals.temp.min, &Globals.temp.max, - &Globals.temp.gstemp); + &Globals->temp.avg, &Globals->temp.std, + &Globals->temp.min, &Globals->temp.max, + &Globals->temp.gstemp); nitems = 5; break; case 3: x=sscanf( inbuf, "%d %f %f %f %f ", &use[0], - &Globals.pat.occur, &Globals.pat.removal, - &Globals.pat.recol[Slope], - &Globals.pat.recol[Intcpt]); + &Globals->pat.occur, &Globals->pat.removal, + &Globals->pat.recol[Slope], + &Globals->pat.recol[Intcpt]); nitems = 4; break; case 4: x=sscanf( inbuf, "%d %f %hu %hu", &use[1], - &Globals.mound.occur, - &Globals.mound.minyr, - &Globals.mound.maxyr); + &Globals->mound.occur, + &Globals->mound.minyr, + &Globals->mound.maxyr); nitems = 3; break; case 5: x=sscanf( inbuf, "%d %f %hu", &use[2], - &Globals.burrow.occur, - &Globals.burrow.minyr); + &Globals->burrow.occur, + &Globals->burrow.minyr); nitems = 2; break; case 6: x=sscanf( inbuf, "%f %f %f %f %f %f", - &Globals.tempparm[CoolSeason][0], - &Globals.tempparm[CoolSeason][1], - &Globals.tempparm[CoolSeason][2], - &Globals.tempparm[WarmSeason][0], - &Globals.tempparm[WarmSeason][1], - &Globals.tempparm[WarmSeason][2]); + &Globals->tempparm[CoolSeason][0], + &Globals->tempparm[CoolSeason][1], + &Globals->tempparm[CoolSeason][2], + &Globals->tempparm[WarmSeason][0], + &Globals->tempparm[WarmSeason][1], + &Globals->tempparm[WarmSeason][2]); nitems = 6; break; } @@ -293,9 +275,9 @@ static void _env_init( void) { } /* end while*/ - Globals.pat.use = itob(use[0]); - Globals.mound.use = itob(use[1]); - Globals.burrow.use = itob(use[2]); + Globals->pat.use = itob(use[0]); + Globals->mound.use = itob(use[1]); + Globals->burrow.use = itob(use[2]); CloseFile(&f); } @@ -317,7 +299,7 @@ static void _plot_init( void) { LogError(logfp, LOGFATAL, "%s: No data found!\n", MyFileName); } - x = sscanf( inbuf, " %f", &Globals.plotsize); + x = sscanf( inbuf, " %f", &Globals->plotsize); if (x < nitems) { LogError(logfp, LOGFATAL, "%s: Incorrect number of fields", MyFileName); @@ -343,7 +325,7 @@ static void _check_species( void) { */ IntS i, cnt, maxage, minage, /* placeholders */ - runyrs = Globals.runModelYears; /* shorthand */ + runyrs = SuperGlobals.runModelYears; /* shorthand */ SppIndex sp; GrpIndex rg; Bool tripped = FALSE; @@ -427,7 +409,7 @@ static void _check_species( void) { RGroup[rg]->max_age = (Species[sp]->max_age) ? max(Species[sp]->max_age, RGroup[rg]->max_age) - : Globals.Max_Age; + : Globals->Max_Age; } RGroup[rg]->kills = (IntUS *) Mem_Calloc(GrpMaxAge(rg), sizeof(IntUS), @@ -702,7 +684,7 @@ static void _setNameLen(char *dest, char *src, Int len) { } /**************************************************************/ -static void _maxrgroupspecies_init( void) { +void maxrgroupspecies_init( void) { /*======================================================*/ FILE *f; @@ -718,7 +700,7 @@ static void _maxrgroupspecies_init( void) { LogError(logfp, LOGFATAL, "%s: Could not read maximum resource groups allowed.", MyFileName); } - if (sscanf(inbuf, "%zu", &Globals.max_rgroups) != 1) { + if (sscanf(inbuf, "%zu", &SuperGlobals.max_rgroups) != 1) { LogError(logfp, LOGFATAL, "%s: Could not read maximum resource groups allowed.", MyFileName); } @@ -726,7 +708,7 @@ static void _maxrgroupspecies_init( void) { LogError(logfp, LOGFATAL, "%s: Could not read maximum resource group name length.", MyFileName); } - if (sscanf(inbuf, "%zu", &Globals.max_groupnamelen) != 1) { + if (sscanf(inbuf, "%zu", &SuperGlobals.max_groupnamelen) != 1) { LogError(logfp, LOGFATAL, "%s: Could not read maximum resource group name length.", MyFileName); } @@ -736,7 +718,7 @@ static void _maxrgroupspecies_init( void) { LogError(logfp, LOGFATAL, "%s: Could not read maximum species allowed per resource group.", MyFileName); } - if (sscanf(inbuf, "%zu", &Globals.max_spp_per_grp) != 1) { + if (sscanf(inbuf, "%zu", &SuperGlobals.max_spp_per_grp) != 1) { LogError(logfp, LOGFATAL, "%s: Could not read maximum species allowed per resource group.", MyFileName); } @@ -744,7 +726,7 @@ static void _maxrgroupspecies_init( void) { LogError(logfp, LOGFATAL, "%s: Could not read maximum individuals allowed per species.", MyFileName); } - if (sscanf(inbuf, "%zu", &Globals.max_indivs_per_spp) != 1) { + if (sscanf(inbuf, "%zu", &SuperGlobals.max_indivs_per_spp) != 1) { LogError(logfp, LOGFATAL, "%s: Could not read maximum individuals allowed per species.", MyFileName); } @@ -752,7 +734,7 @@ static void _maxrgroupspecies_init( void) { LogError(logfp, LOGFATAL, "%s: Could not read maximum species name length.", MyFileName); } - if (sscanf(inbuf, "%zu", &Globals.max_speciesnamelen) != 1) { + if (sscanf(inbuf, "%zu", &SuperGlobals.max_speciesnamelen) != 1) { LogError(logfp, LOGFATAL, "%s: Could not read maximum species name length.", MyFileName); } @@ -792,8 +774,8 @@ static void _rgroup_init( void) { MyFileName = Parm_name(F_RGroup); f = OpenFile(MyFileName, "r"); - name = (char *)Mem_Calloc(Globals.max_groupnamelen + 1, sizeof(char), "_rgroup_init"); - RGroup = (GroupType **)Mem_Calloc(Globals.max_rgroups, sizeof(GroupType *), "_rgroup_init"); + name = (char *)Mem_Calloc(SuperGlobals.max_groupnamelen + 1, sizeof(char), "_rgroup_init"); + RGroup = (GroupType **)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(GroupType *), "_rgroup_init"); /* ------------------------------------------------------------*/ /* Install all the defined groups, except for dry/wet/norm parms */ @@ -910,7 +892,7 @@ static void _rgroup_add1( char name[], RealF space, RealF density, RGroup[rg]->max_stretch = (IntS) stretch; RGroup[rg]->max_spp_estab = (IntS) estab; // input of `density` is in units of [# / m2]; convert to units of [# / plot] - RGroup[rg]->max_density = density * Globals.plotsize; // density per plot + RGroup[rg]->max_density = density * Globals->plotsize; // density per plot RGroup[rg]->max_per_sqm = density; // density per square-meter RGroup[rg]->use_mort = itob(mort); RGroup[rg]->slowrate = slow; @@ -1003,10 +985,10 @@ static void _rgroup_addsucculent( char name[], MyFileName, name); } RGroup[rg]->succulent = TRUE; - Succulent.growth[Slope] = wslope; - Succulent.growth[Intcpt] = wint; - Succulent.mort[Slope] = dslope; - Succulent.mort[Intcpt] = dint; + Succulent->growth[Slope] = wslope; + Succulent->growth[Intcpt] = wint; + Succulent->mort[Slope] = dslope; + Succulent->mort[Intcpt] = dint; } /**************************************************************/ @@ -1041,14 +1023,14 @@ static void _species_init( void) { viable, pseed; RealF irate, ratep, estab, minb, maxb, cohort, xdecay, - p1, p2, p3, p4, p5, p6, p7; + p1, p2, p3, p4, p5, p6, p7, p8; float var; char clonal[5]; MyFileName = Parm_name( F_Species); f = OpenFile(MyFileName, "r"); - name = (char *)Mem_Calloc(Globals.max_speciesnamelen + 1, sizeof(char), "_species_init"); + name = (char *)Mem_Calloc(SuperGlobals.max_speciesnamelen + 1, sizeof(char), "_species_init"); Species = (SpeciesType **)Mem_Calloc(MAX_SPECIES, sizeof(SpeciesType *), "_species_init"); while( readspp) { @@ -1109,7 +1091,7 @@ static void _species_init( void) { Species[sp]->received_prob = 0; Species[sp]->cohort_surv = cohort; // input of `pseed` is in units of [# / m2]; convert to units of [# / plot] - Species[sp]->pseed = pseed * Globals.plotsize; + Species[sp]->pseed = pseed * Globals->plotsize; /* Species[sp]->ann_mort_prob = (age > 0) ? -log(cohort)/age : 0.0; @@ -1165,7 +1147,7 @@ static void _species_init( void) { Species[sp]->exp_decay = xdecay; Species[sp]->seedprod = (IntUS *) Mem_Calloc( viable, sizeof(IntUS), "species_init()"); Species[sp]->var = var; - Species[sp]->pseed = pseed / Globals.plotsize; + Species[sp]->pseed = pseed / Globals->plotsize; } /* end while readspp*/ @@ -1208,39 +1190,45 @@ static void _species_init( void) { MyFileName); } - /* ------------------------------------------------- */ - /* ------- read the seed dispersal parameters ------ */ - sppok = readspp = TRUE; - while( readspp ) { - if( !GetALine(f, inbuf) ) {sppok=FALSE; break;} - if( !isnull(strstr(inbuf,"[end]")) ) { - readspp=FALSE; - continue; - } + /* ------------------------------------------------- */ + /* ------- read the seed dispersal parameters ------ */ + sppok = readspp = TRUE; + while( readspp ) { + if( !GetALine(f, inbuf) ) { + sppok=FALSE; break; + } + if( !isnull(strstr(inbuf,"[end]")) ) { + readspp=FALSE; + continue; + } - x = sscanf( inbuf, "%s %hd %f %f %f %f %f %f %f", - name, &turnondispersal, &p1, &p2, &p3, &p4, &p5, &p6, &p7); - if(x < 9) - LogError(logfp, LOGFATAL, "%s: Too few columns in species seed dispersal inputs", MyFileName); - - sp = Species_Name2Index(name); - if(sp < 0) - LogError(logfp, LOGFATAL, "%s: Mismatched name (%s) for species seed dispersal inputs", MyFileName, name); - - Species[sp]->use_dispersal = itob(turnondispersal); - Species[sp]->allow_growth = TRUE; - Species[sp]->sd_sgerm = FALSE; - - Species[sp]->sd_Param1 = p1; - Species[sp]->sd_PPTdry = p2; - Species[sp]->sd_PPTwet = p3; - Species[sp]->sd_Pmin = p4; - Species[sp]->sd_Pmax = p5; - Species[sp]->sd_H = p6; - Species[sp]->sd_VT = p7; - } - if(!sppok) + x = sscanf( inbuf, "%s %hd %f %f %f %f %f %f %f %f", + name, &turnondispersal, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8); + if(x < 10) { + LogError(logfp, LOGFATAL, "%s: Too few columns in species seed dispersal inputs", MyFileName); + } + + sp = Species_Name2Index(name); + if(sp < 0){ + LogError(logfp, LOGFATAL, "%s: Mismatched name (%s) for species seed dispersal inputs", MyFileName, name); + } + + Species[sp]->use_dispersal = itob(turnondispersal); + Species[sp]->allow_growth = TRUE; + Species[sp]->sd_sgerm = FALSE; + + Species[sp]->sd_Param1 = p1; + Species[sp]->sd_PPTdry = p2; + Species[sp]->sd_PPTwet = p3; + Species[sp]->sd_Pmin = p4; + Species[sp]->sd_Pmax = p5; + Species[sp]->sd_H = p6; + Species[sp]->sd_VT = p7; + Species[sp]->sd_VW = p8; + } + if(!sppok) { LogError(logfp, LOGFATAL, "%s: Incorrect/incomplete input in species seed dispersal input", MyFileName); + } Mem_Free(name); diff --git a/ST_progressBar.c b/ST_progressBar.c new file mode 100644 index 00000000..3c6d78d6 --- /dev/null +++ b/ST_progressBar.c @@ -0,0 +1,124 @@ +/**************************************************************************/ +/* ST_progressBar.c + Function definitions for a progress bar printed to the terminal. + See ST_progressBar.h for a description of how to add a new Status. + + \author Chandler Haukap in August 2019 + */ +/**************************************************************************/ + +#include "ST_progressBar.h" +#include "ST_defines.h" +#include "ST_globals.h" +#include + +/*************** Local Function(s). Treat these as private. ***************/ + +double _calculateProgress(int innerLoopIteration, int outerLoopIteration, Status status); +double _calculateInitializationProgress(int year); +double _calculateSimulationProgress(int year, int iteration); + +/*********************** Function Definitions *****************************/ + +/* Log the program's progress using a progress bar. + Param iteration: integer greater than 0. Input 0 if and only if the program + is not currently in an iteration loop. + Param year: integer greater than 0. Input 0 if and only if the program is + not currently in a years loop. + Param status: Use the "Status" enum to choose a value. */ +void logProgress(int iteration, int year, Status status){ + static char progressString[256]; + int index = 0; // Where we are in progressString + Bool needsProgressBar = FALSE; // By default we do not need a progress bar + progressString[0] = '\0'; // Empty the string + iteration--; // iteration loops are 1 indexed, but we need 0 indexing. + + switch(status){ + case INITIALIZATION: + strcpy(progressString, "Initializing |"); + index += 14; // We have copied over 16 characters + needsProgressBar = TRUE; + break; + case SIMULATION: + strcpy(progressString, "Simulating |"); + index += 14; // We have copied over 12 characters + needsProgressBar = TRUE; + break; + case OUTPUT: + strcpy(progressString, "Writing files"); + index += 13; // We have copied over 12 characters + break; + case DONE: + strcpy(progressString, "Done"); + // We need to pad the string with spaces to make sure we overwrite any progress bars. + for(index = 4; index < 40; ++index) progressString[index] = ' '; + break; + default: + break; + } + + // If our program is currently in a looping state we can make a progress bar using year and iteration. + if(needsProgressBar){ + int numberOfCharacters = 0; + double percentComplete = _calculateProgress(year, iteration, status); + // Add '=' characters for every 5% complete. + while(percentComplete > 0){ + progressString[index] = '='; + index++; + numberOfCharacters++; + percentComplete -= 5; + } + // Add spaces until we hit 20 characters + while(numberOfCharacters < 20){ + progressString[index] = ' '; + numberOfCharacters++; + index++; + } + progressString[index++] = '|'; + progressString[index++] = '\0'; + } + + printf("\r%s", progressString); // print the string we generated + fflush(stdout); // Explicitly print the output. + + // If we are done we want to print a newline character so the terminal isn't appended to our "Done" string. + if(status == DONE){ + printf("\n"); + } +} + +/* Returns a double between 0 and 100 representing how close the program is to completing a given loop. + * + * \param innerLoopIteration is the iteration of the inner loop. + * \param outerLoopIteration is the iteration of the outer loop. + * \param status: Use the "status" enumerator. Valid options are SPINUP or SIMULATION. + * + * Example usage for a loop with the structure "For iterations { for years {...} }": + * _calculateProgress(, , SIMULATION); + */ +double _calculateProgress(int innerLoopIteration, int outerLoopIteration, Status status){ + double percentComplete; + if(status == INITIALIZATION){ + percentComplete = _calculateInitializationProgress(innerLoopIteration); + } else if(status == SIMULATION) { + percentComplete = _calculateSimulationProgress(innerLoopIteration, outerLoopIteration); + } else { + return 0; // No other Status has defined how to calculate progress. + } + return percentComplete; +} + +/* Algorithm for calculating how far along initialization is. + Returns a percentage between 0 and 100. */ +double _calculateInitializationProgress(int year){ + return (year / (double) SuperGlobals.runInitializationYears) * 100; +} + +/* Algorithm for calculating how far along the simulation is. + Returns a percentage between 0 and 100. */ +double _calculateSimulationProgress(int year, int iteration){ + double prog = ((iteration * SuperGlobals.runModelYears) + year) + / (double) (SuperGlobals.runModelIterations * SuperGlobals.runModelYears); + + return prog * 100; +} \ No newline at end of file diff --git a/ST_progressBar.h b/ST_progressBar.h new file mode 100644 index 00000000..f9c7bd78 --- /dev/null +++ b/ST_progressBar.h @@ -0,0 +1,36 @@ +/******************************************************************/ +/* ST_progressBar.h + Defines all exported objects from ST_progressBar.c. + + TO ADD STATUSES: + Adding a Status is easy. Start by adding your entry to the + Status enum. Then, define what message your status should + print in the switch statement in logProgress() defined in + ST_progressBar.c. Finally, if your Status requires a + progress bar, create a function for calculating progress + in ST_progressBar.c then add your function to + _calculateProgress(). + + \author Chandler Haukap in August 2019 +*/ +/******************************************************************/ + +#ifndef PROGRESSBAR_H +#define PROGRESSBAR_H + +/*********************** Enumerator(s) ****************************/ + +/* States of the program that the progress bar recognizes. */ +typedef enum +{ + INITIALIZATION, + SIMULATION, + OUTPUT, + DONE +} Status; + +/******************** Exported Function(s) ************************/ + +void logProgress(int iteration, int year, Status status); + +#endif \ No newline at end of file diff --git a/ST_resgroups.c b/ST_resgroups.c index c16a508f..07494905 100644 --- a/ST_resgroups.c +++ b/ST_resgroups.c @@ -44,6 +44,7 @@ void rgroup_ResPartIndiv(void); void rgroup_DropSpecies(SppIndex sp); void rgroup_AddSpecies(GrpIndex rg, SppIndex sp); void rgroup_Extirpate(GrpIndex rg); +void copy_rgroup(const GroupType* src, GroupType* dest); /*********** Locally Used Function Declarations ************/ /***********************************************************/ @@ -205,13 +206,13 @@ static void _add_annual_seedprod(SppIndex sp, RealF lastyear_relsize) { * that can establish. Otherwise, this year's seed production is a function * of the number of seeds produced per unit biomass multiplied by species biomass * (maximum species biomass * last year's species relative size). */ - if (Globals.currYear == 1) { + if (Globals->currYear == 1) { s->seedprod[0] = RandUniIntRange(1, s->max_seed_estab, &resgroups_rng); //printf("Species name=%s ,currYear =1 so new calculated value s->seedprod[%u]= %hu , s->max_seed_estab =%hu\n", s->name, i, s->seedprod[i], s->max_seed_estab); } else { s->seedprod[0] = (IntU) (s->pseed * s->mature_biomass * lastyear_relsize); - //printf("Species name=%s ,currYear=%hu so new calculated value s->seedprod[%u]= %hu , s->max_seed_estab =%hu, lastyear_relsize=%.5f\n", s->name, Globals.currYear, i, s->seedprod[i], s->max_seed_estab, lastyear_relsize); + //printf("Species name=%s ,currYear=%hu so new calculated value s->seedprod[%u]= %hu , s->max_seed_estab =%hu, lastyear_relsize=%.5f\n", s->name, Globals->currYear, i, s->seedprod[i], s->max_seed_estab, lastyear_relsize); } } @@ -298,8 +299,8 @@ void rgroup_ResPartIndiv(void) { *size_base, /* biomass of the functional group */ *size_obase; /* biomass of functional groups that can use extra resources */ - size_base = (RealF *)Mem_Calloc(Globals.max_rgroups, sizeof(RealF), "rgroup_ResPartIndiv"); - size_obase = (RealF *)Mem_Calloc(Globals.max_rgroups, sizeof(RealF), "rgroup_ResPartIndiv"); + size_base = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF), "rgroup_ResPartIndiv"); + size_obase = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF), "rgroup_ResPartIndiv"); /* Divide each group's normal resources to individuals */ ForEachGroup(rg) { @@ -455,7 +456,7 @@ void rgroup_Grow(void) { continue; /* Succulents don't grow if conditions are wet */ - if (g->succulent && Env.wet_dry == Ppt_Wet) + if (g->succulent && Env->wet_dry == Ppt_Wet) continue; /* Increment size of each individual in response to normal resources */ @@ -467,7 +468,7 @@ void rgroup_Grow(void) { continue; /* Modify growth rate by temperature calculated in Env_Generate() */ - tgmod = (s->tempclass == NoSeason) ? 1. : Env.temp_reduction[s->tempclass]; + tgmod = (s->tempclass == NoSeason) ? 1. : Env->temp_reduction[s->tempclass]; /* Now increase size of the individual plants of current species */ ForEachIndiv(ndv, s) { @@ -618,7 +619,7 @@ void rgroup_Establish(void) { GroupType *g; /* Cannot establish if plot is still in disturbed state*/ - if (Plot.disturbed > 0) { + if (Plot->disturbed > 0) { ForEachGroup(rg) RGroup[rg]->regen_ok = FALSE; return; /* skip regen for all */ @@ -633,7 +634,7 @@ void rgroup_Establish(void) { g->regen_ok = TRUE; /* default */ g->min_res_req = g->space; /* reset min_res_req, if it was modified last year */ - if (Globals.currYear < RGroup[rg]->startyr) { + if (Globals->currYear < RGroup[rg]->startyr) { g->regen_ok = FALSE; } else { @@ -648,7 +649,6 @@ void rgroup_Establish(void) { /* Establishment for species that belong to annual functional groups*/ if (Species[sp]->max_age == 1) { - //printf("Globals.currYear = %hu, call to _add_annuals sp=%d Species[sp]->lastyear_relsize : %.5f \n", Globals.currYear, sp, Species[sp]->lastyear_relsize); num_est = _add_annuals(rg, sp, Species[sp]->lastyear_relsize); } @@ -658,9 +658,6 @@ void rgroup_Establish(void) { } if (num_est) { - /* printf("%d %d %d %d\n", - Globals.currIter, Globals.currYear, sp, num_est); */ - Species_Add_Indiv(sp, num_est); species_Update_Estabs(sp, num_est); } @@ -724,8 +721,8 @@ void rgroup_IncrAges(void) LogError(logfp, LOGWARN, "%s grown older than max_age (%d > %d). Iter=%d, Year=%d\n", Species[ndv->myspecies]->name, ndv->age, - Species[ndv->myspecies]->max_age, Globals.currIter, - Globals.currYear); + Species[ndv->myspecies]->max_age, Globals->currIter, + Globals->currYear); } } } @@ -860,9 +857,9 @@ static GroupType *_create(void) GroupType *p; p = (GroupType *) Mem_Calloc(1, sizeof(GroupType), "_create"); - p->name = (char *) Mem_Calloc(Globals.max_groupnamelen + 1, sizeof(char), "_create"); - p->est_spp = (SppIndex *) Mem_Calloc(Globals.max_spp_per_grp, sizeof(SppIndex), "_create"); - p->species = (SppIndex *) Mem_Calloc(Globals.max_spp_per_grp, sizeof(SppIndex), "_create"); + p->name = (char *) Mem_Calloc(SuperGlobals.max_groupnamelen + 1, sizeof(char), "_create"); + p->est_spp = (SppIndex *) Mem_Calloc(SuperGlobals.max_spp_per_grp, sizeof(SppIndex), "_create"); + p->species = (SppIndex *) Mem_Calloc(SuperGlobals.max_spp_per_grp, sizeof(SppIndex), "_create"); return (p); @@ -884,13 +881,13 @@ GrpIndex RGroup_New(void) /* Chris Bennett @ LTER-CSU 6/15/2000 */ /*------------------------------------------------------*/ - GrpIndex i = (GrpIndex) Globals.grpCount; + GrpIndex i = (GrpIndex) Globals->grpCount; - if (++Globals.grpCount > Globals.max_rgroups) + if (++Globals->grpCount > SuperGlobals.max_rgroups) { LogError(logfp, LOGFATAL, "Too many groups specified (>%d)!\n" "You must adjust MAX_RGROUPS in maxrgroupspecies.in!", - Globals.max_rgroups); + SuperGlobals.max_rgroups); } RGroup[i] = _create(); @@ -996,6 +993,100 @@ void rgroup_Extirpate(GrpIndex rg) } +/* Copy one GroupType's variables to another GroupType. Both GroupTypes must be + * allocated before calling this function. + * + * \param src is the source of the data to be copied over. + * \param dest is destination to recieve the data. + * + * \sideeffect dest will be reallocated to the size of src, and all fields of + * dest will be overwritten with src's data. + */ +void copy_rgroup(const GroupType* src, GroupType* dest){ + int i; + + /* The first step of this algorithm is to deallocate dest's memory so it + * can be reallocated to the size of src. If dest and src are the same + * the net sum of this function would be to deallocate all of the fields + * of the GroupType. */ + if(src == dest){ + return; + } + + /* -------------- Copy any arrays -------------- */ + if(MortFlags.summary){ + Mem_Free(dest->kills); + dest->kills = (IntUS*) Mem_Calloc(GrpMaxAge(src->grp_num), sizeof(IntUS), "copy_rgroup: kills"); + for(i = 0; i < GrpMaxAge(src->grp_num); ++i){ + dest->kills[i] = src->kills[i]; + } + } + + Mem_Free(dest->est_spp); + dest->est_spp = (SppIndex*) Mem_Calloc(src->est_count, sizeof(SppIndex), "copy_rgroup: est_spp"); + for(i = 0; i < src->est_count; ++i){ + dest->est_spp[i] = src->est_spp[i]; + } + + /* ------------- Copy all fields --------------- */ + dest->cheatgrass_coefficient = src->cheatgrass_coefficient; + dest->depth = src->depth; + dest->est_annually = src->est_annually; + dest->est_count = src->est_count; + dest->estabs = src->estabs; + dest->extirp = src->extirp; + dest->extirpated = src->extirpated; + dest->grazingfreq_startyr = src->grazingfreq_startyr; + dest->grazingfrq = src->grazingfrq; + dest->grp_num = src->grp_num; + dest->ignition = src->ignition; + dest->killfreq = src->killfreq; + dest->killfreq_startyr = src->killfreq_startyr; + dest->killyr= src->killyr; + dest->max_age = src->max_age; + dest->max_bmass = src->max_bmass; + dest->max_density = src->max_density; + dest->max_per_sqm = src->max_per_sqm; + dest->max_spp = src->max_spp; + dest->max_spp_estab = src->max_spp_estab; + dest->max_stretch = src->max_stretch; + dest->min_res_req = src->min_res_req; + dest->mm_extra_res = src->mm_extra_res; + strcpy(dest->name, src->name); + dest->ppt_intcpt[0] = src->ppt_intcpt[0]; + dest->ppt_intcpt[1] = src->ppt_intcpt[1]; + dest->ppt_intcpt[2] = src->ppt_intcpt[2]; + dest->ppt_slope[0] = src->ppt_slope[0]; + dest->ppt_slope[1] = src->ppt_slope[1]; + dest->ppt_slope[2] = src->ppt_slope[2]; + dest->pr = src->pr; + dest->prescribedfire = src->prescribedfire; + dest->proportion_grazing = src->proportion_grazing; + dest->proportion_killed = src->proportion_killed; + dest->proportion_recovered = src->proportion_recovered; + dest->regen_ok = src->regen_ok; + dest->res_avail = src->res_avail; + dest->res_extra = src->res_extra; + dest->res_required = src->res_required; + dest->rgroupFractionOfVegTypeBiomass = src->rgroupFractionOfVegTypeBiomass; + dest->slowrate = src->slowrate; + dest->startyr = src->startyr; + dest->succulent = src->succulent; + dest->use_extra_res = src->use_extra_res; + dest->use_me = src->use_me; + dest->use_mort = src->use_mort; + dest->veg_prod_type = src->veg_prod_type; + dest->wild_fire_slope = src->wild_fire_slope; + dest->wildfire = src->wildfire; + dest->xgrow = src->xgrow; + dest->yrs_neg_pr = src->yrs_neg_pr; + + /* ---------------- Copy Species Array ----------------- */ + for(i = 0; i < SuperGlobals.max_spp_per_grp; ++i){ + dest->species[i] = src->species[i]; + } +} + /**************************************************************/ void RGroup_Kill(GrpIndex rg) { diff --git a/ST_seedDispersal.c b/ST_seedDispersal.c new file mode 100644 index 00000000..dd8c256b --- /dev/null +++ b/ST_seedDispersal.c @@ -0,0 +1,330 @@ +/********************************************************************************* + * ST_seedDispersal.c + * + * Contains definitions for all functions belonging to the seed dispersal module. + *********************************************************************************/ + +#include "ST_globals.h" +#include "ST_defines.h" +#include "ST_grid.h" +#include "ST_seedDispersal.h" +#include "rands.h" +#include "myMemory.h" + +int _do_bulk_dispersal(SppIndex sp); +void _do_precise_dispersal(int leftoverSeeds, SppIndex sp); +float _cell_dist(int row1, int row2, int col1, int col2, float cellLen); + +/* RNG unique to seed dispersal. */ +pcg32_random_t dispersal_rng; + +/* Derives the probabilities that a given cell will disperse seeds to any other cell. + results of this function can be accessed using + gridCells[a][b].mySeedDispersal[s].dispersalProb[c][d] + where (a,b) are the coordinates of the sender, + (b, c) are the coordinates of the receiver, + and s is the species. */ +void initDispersalParameters(void) +{ + int senderRow, senderCol, receiverRow, receiverCol, MAXDP, maxCells; + SppIndex sp; + double MAXD; /* maximum seed dispersal distance for a given species */ + double maxRate; /* Dispersability of the seeds */ + double plotWidth; /* width of the plots (all plots are equal and square) */ + double distanceBetweenPlots; /* distance between the sender and the receiver */ + CellType* sender; + + RandSeed(SuperGlobals.randseed, &dispersal_rng); + + /* sender denotes that these loops refer to the cell distributing seeds */ + for(senderRow = 0; senderCol < grid_Rows; ++senderRow){ + for(senderCol = 0; senderCol < grid_Cols; ++senderCol){ + /* Cell is loaded to ensure the global Species pointer points to a valid SpeciesType so the + ForEachSpecies loop is able to iterate. */ + load_cell(senderRow, senderCol); + sender = &gridCells[senderRow][senderCol]; + + /* Allocate seed dispersal information. */ + sender->mySeedDispersal = Mem_Calloc(MAX_SPECIES, sizeof(Grid_SD_St), "initDispersalParameters"); + + ForEachSpecies(sp){ + if (!(Species[sp]->use_me && Species[sp]->use_dispersal)){ + continue; + } + + /* These are the three values we need to calculate the probability of dispersal + * according to EQ 5 in Coffin & Lauenroth 1989. */ + MAXD = ((Species[sp]->sd_H * Species[sp]->sd_VW) / Species[sp]->sd_VT) / 100.0; // divided by 100 to convert from cm to m. + maxRate = -(log(0.005) / MAXD); + plotWidth = sqrt(Globals->plotsize); + MAXDP = (int) ceil(MAXD / plotWidth); //MAXD in terms of plots... rounds up to the nearest integer + maxCells = (int) pow((MAXDP * 2) + 1.0, 2.0); + + /* Allocate the dispersalProb 2d array */ + sender->mySeedDispersal[sp].dispersalProb = Mem_Calloc(grid_Rows, + sizeof(double*), "initDispersalParameters: dispersalProb"); + for(receiverRow = 0; receiverRow < grid_Rows; ++receiverRow){ + sender->mySeedDispersal[sp].dispersalProb[receiverRow] = + Mem_Calloc(grid_Cols, sizeof(double), "initDispersalParameters: dispersalProb[i]"); + } + + /* Loop through all possible recipients of seeds. */ + for(receiverRow = 0; receiverRow < grid_Rows; ++receiverRow){ + for(receiverCol = 0; receiverCol < grid_Cols; ++receiverCol){ + if(senderRow == receiverRow && senderCol == receiverCol){ + continue; // No need to calculate a probability for dispersal to itself + } + + distanceBetweenPlots = _cell_dist(senderRow, receiverRow, senderCol, receiverCol, plotWidth); + + /* The value that we are after should be saved to the sender cell. + * this equation comes directly from equation 4 in Coffin and Lauenroth 1989. */ + sender->mySeedDispersal[sp].dispersalProb[receiverRow][receiverCol] + = (distanceBetweenPlots > MAXD) ? (0.0) : (exp(-maxRate * distanceBetweenPlots)); + } + } + } + } + } + unload_cell(); +} + +/* Perform seed dispersal during the simulation. This is NOT functional yet. */ +void disperseSeeds(void) +{ + /************ TODO: overhaul seed dispersal. This block prevents seed dispersal from running. **************/ + printf("\nSeed dispersal during the simulation is not yet functional.\n" + "Check out GitHub for updates on this feature.\n"); + UseSeedDispersal = FALSE; + return; + /***********************************************************************************************************/ + +/* TODO: discuss this implementation: + SppIndex sp; + ForEachSpecies(sp){ + int leftovers = _do_bulk_dispersal(sp); + _do_precise_dispersal(leftovers, sp); + } +*/ + +/* + float biomass, randomN, LYPPT, presentProb, receivedProb; + int i, j, germ, sgerm, year, row, col; + SppIndex s; + CellType *cell; + + // Load the first cell so we can access seedling_estab_prob and currYear, + // which are not specific to each cell. + load_cell(0, 0); + + if (Globals->currYear == 1) + { //since we have no previous data to go off of, use the current years... + for (i = 0; i < grid_Cells; i++) + { + row = i / grid_Cols; + col = i % grid_Cols; + cell = &gridCells[row][col]; + + load_cell(row, col); + + ForEachSpecies(s) + { + if (!(Species[s]->use_me && Species[s]->use_dispersal)) + continue; + Species[s]->allow_growth = Species[s]->sd_sgerm = + 1;// since it's the first year, we have to allow growth... + if (UseDisturbances) + // RGroup[x]->killyr is the same for all x + if (1 == RGroup[0]->killyr) + Species[s]->allow_growth = 0; + cell->mySeedDispersal[s].lyppt = Env->ppt; + } + } + } + else + { + // figure out whether or not to allow growth for the current year... based upon whether the species already has plants or germination allowed this year and seeds received last year... + ForEachSpecies(s) + { + + if (!(Species[s]->use_me && Species[s]->use_dispersal)) + continue; + + // germination probability + randomN = RandUni(&grid_rng); + germ = LE(randomN, Species[s]->seedling_estab_prob); + + year = Globals->currYear - 1; + + for (i = 0; i < grid_Cells; i++) + { + row = i / grid_Cols; + col = i % grid_Cols; + cell = &gridCells[row][col]; + + load_cell(row, col); + + if (Globals->currYear <= SuperGlobals.runInitializationYears) + { + cell->mySeedDispersal[s].seeds_present = 1; + } + else if (Globals->currYear <= SuperGlobals.runInitializationYears + && cell->mySpeciesInit.shouldBeInitialized[s]) + { + cell->mySeedDispersal[s].seeds_present = 1; + } + + sgerm = (cell->mySeedDispersal[s].seeds_present + || cell->mySeedDispersal[s].seeds_received) && germ; //refers to whether the species has seeds available from the previous year and conditions are correct for germination this year + Species[s]->allow_growth = FALSE; + biomass = getSpeciesRelsize(s) + * Species[s]->mature_biomass; + + if (UseDisturbances) + { + if ((sgerm || year < RGroup[0]->killyr + || RGroup[0]->killyr <= 0 || GT(biomass, 0.0)) + && (year != RGroup[0].killyr)) + { + //commented above one condition as it was causing a bug there, next year of killing year will make + //allow_growth flag to false as year = Globals->currYear - 1 , so for example if killing year= 6 and Globals->currYear=7 then here + // year variable will be 7-1 =6 that is equal to killing year 6, so this condition (year != RGroup[0].killyr) + //will fail and allow_growth will not become TRUE, then when Globals.currYear=8 this allow_growth= FALSE will carry forward and there will no call + // to other functions. Last year size will carry forward so in final output year 7 and year 8 will + // have same output that is not correct. + Species[s]->allow_growth = TRUE; + } + + } + else if (sgerm || GT(biomass, 0.0)) + Species[s]->allow_growth = TRUE; + Species[s]->sd_sgerm = sgerm; //based upon whether we have received/produced seeds that germinated + } + } + + } + + // calculate whether or not seeds were received/produced this year, this data is used the next time the function is called + ForEachSpecies(s) + { + if (!(Species[s]->use_me && Species[s]->use_dispersal)) + continue; + + IndivType* indiv; + + // figure out which species in each cell produced seeds... + for (i = 0; i < grid_Cells; i++) + { + row = i / grid_Cols; + col = i % grid_Cols; + cell = &gridCells[row][col]; + + load_cell(row, col); + + cell->mySeedDispersal[s].seeds_present = cell->mySeedDispersal[s].seeds_received = + Species[s]->received_prob = 0; + + biomass = 0; //getting the biggest individual in the species... + ForEachIndiv(indiv, Species[s]) + if (indiv->relsize * Species[s]->mature_biomass + > biomass) + biomass = indiv->relsize + * Species[s]->mature_biomass; + + if (GE(biomass, + Species[s]->mature_biomass + * Species[s]->sd_Param1)) + { + randomN = RandUni(&grid_rng); + + LYPPT = cell->mySeedDispersal[s].lyppt; + float PPTdry = Species[s]->sd_PPTdry, PPTwet = + Species[s]->sd_PPTwet; + float Pmin = Species[s]->sd_Pmin, Pmax = + Species[s]->sd_Pmax; + + //p3 = Pmin, if LYPPT < PPTdry + //p3 = 1 - (1-Pmin) * exp(-d * (LYPPT - PPTdry)) with d = - ln((1 - Pmax)/(1 - Pmin)) / (PPTwet - PPTdry), if PPTdry <= LYPPT <= PPTwet + //p3 = Pmax, if LYPPT > PPTwet + + presentProb = 0.0; + if (PPTdry <= LYPPT && LYPPT <= PPTwet) + { + float d = -log(((1 - Pmax) / (1 - Pmin))) + / (PPTwet - PPTdry); //log is the natural log in STD c's math.h + presentProb = 1 - (1 - Pmin) * exp((-d * (LYPPT - PPTdry))); + } + else if (LYPPT < PPTdry) + presentProb = Pmin; + else if (LYPPT > PPTwet) + presentProb = Pmax; + + if (LE(randomN, presentProb)) + cell->mySeedDispersal[s].seeds_present = 1; + } + } + + // figure out which species in each cell received seeds... + for (i = 0; i < grid_Cells; i++) + { + row = i / grid_Cols; + col = i % grid_Cols; + cell = &gridCells[row][col]; + + load_cell(row, col); + + if (cell->mySeedDispersal[s].seeds_present) + continue; + receivedProb = 0; + + for (j = 0; j < cell->mySeedDispersal[s].size; j++) + if (cell->mySeedDispersal[cell->mySeedDispersal[s].cells[j]].seeds_present) + receivedProb += cell->mySeedDispersal[s].dispersalProb[j]; + + randomN = RandUni(&grid_rng); + if (LE(randomN, receivedProb) && !ZRO(receivedProb)) + cell->mySeedDispersal[s].seeds_received = 1; + else + cell->mySeedDispersal[s].seeds_received = 0; + + Species[s]->received_prob = receivedProb; + } + } + + unload_cell(); +*/ +} + +int _do_bulk_dispersal(SppIndex sp){ + return 0; +} + +void _do_precise_dispersal(int leftoverSeeds, SppIndex sp){ + /* This function is not implemented yet. */ + return; +} + +/* Returns the distance in meters between two cells. + To calculate the distance between cells (a,b) and (c,d) with plot width w, + input _cell_dist(a, c, b, d, w) */ +float _cell_dist(int row1, int row2, int col1, int col2, float cellLen) +{ + double rowDist = row1 - row2; + double colDist = col1 - col2; + + //returns the distance between the two grid cells + if (row1 == row2) + { + return (abs(colDist) * cellLen); + } + else if (col1 == col2) + { + return (abs(rowDist) * cellLen); + } + else + { // row1 != row2 && col1 != col2 + //the problem can be thought of in terms of a right triangle... + //using the pythagorean theorem: c = sqrt(a^2 + b^2)... c (the hypotenuse) represents the distance that we need. a is the distance between columns and b is the distance between rows. + return sqrt(pow(abs(colDist)*cellLen, 2.0) + pow(abs(rowDist)*cellLen, 2.0)); + } +} \ No newline at end of file diff --git a/ST_seedDispersal.h b/ST_seedDispersal.h new file mode 100644 index 00000000..0e1b84d1 --- /dev/null +++ b/ST_seedDispersal.h @@ -0,0 +1,31 @@ +/********************************************************************************* + * ST_seedDispersal.h + * + * Contains declarations for exported functions from the seed dispersal module. + * It also contains the declaration for the UseSeedDispersal flag and the + * seed dispersal struct. + *********************************************************************************/ + +#ifndef SEEDDISPERSAL_H +#define SEEDDISPERSAL_H + +/* Holds seed dispersal information. */ +struct _grid_sd_struct +{ //for seed dispersal + /* TRUE if seeds are present. */ + Bool seeds_present; + /* TRUE if this cell has recieved any seeds. */ + Bool seeds_received; + /* dispersalProb[row][col] = the probability that this cell will disperse seeds to cell (row,col). */ + double **dispersalProb; + /* Last year's precipitation. */ + double lyppt; +}typedef Grid_SD_St; + +/* TRUE if we should run seed dispersal between years during the main simulation. */ +Bool UseSeedDispersal; + +void disperseSeeds(void); +void initDispersalParameters(void); + +#endif \ No newline at end of file diff --git a/ST_species.c b/ST_species.c index 5b6fee26..52cc86f2 100644 --- a/ST_species.c +++ b/ST_species.c @@ -23,6 +23,8 @@ #include "myMemory.h" #include "rands.h" #include "sw_src/pcg/pcg_basic.h" +#include "ST_initialization.h" +#include "ST_seedDispersal.h" extern pcg32_random_t species_rng; @@ -41,6 +43,7 @@ void indiv_proportion_Grazing(IndivType *ndv, RealF proportionGrazing); void _delete(IndivType *ndv); void save_annual_species_relsize(void); +void copy_individual(const IndivType* src, IndivType* dest); /*------------------------------------------------------*/ /* Modular functions only used on one or two specific */ @@ -49,6 +52,7 @@ void save_annual_species_relsize(void); void species_Update_Kills(SppIndex sp, IntS age); void species_Update_Estabs(SppIndex sp, IntS num); SppIndex species_New(void); +void copy_species(const SpeciesType* src, SpeciesType* dest); /*********** Locally Used Function Declarations ************/ /***********************************************************/ @@ -67,7 +71,7 @@ IntS Species_NumEstablish(SppIndex sp) /*------------------------------------------------------*/ //special conditions if we're using the grid and seed dispersal options (as long as its not during the spinup, because we dont use seed dispersal during spinup) - if (UseGrid && UseSeedDispersal && !DuringSpinup) { + if (UseGrid && UseSeedDispersal && !DuringInitialization) { if (Species[sp]->sd_sgerm) { if (Species[sp]->max_seed_estab <= 1) { @@ -238,9 +242,9 @@ SppIndex species_New(void) /* Chris Bennett @ LTER-CSU 6/15/2000 */ /*------------------------------------------------------*/ - SppIndex i = (SppIndex) Globals.sppCount; + SppIndex i = (SppIndex) Globals->sppCount; - if (++Globals.sppCount > MAX_SPECIES) + if (++Globals->sppCount > MAX_SPECIES) { LogError(logfp, LOGFATAL, "Too many species specified (>%d)!\n" "You must adjust MAX_SPECIES and recompile!\n", @@ -252,6 +256,119 @@ SppIndex species_New(void) return i; } +/* Copy one Species' information to another Species. Note that both Species MUST be allocated. */ +void copy_species(const SpeciesType* src, SpeciesType* dest){ + int i; + IndivType *srcIndv, *destIndv, *next; + + // Error checking. If src == dest we would just end up loosing the linked list and some other variables. + if(!src || src == dest){ + return; + } + + /* ---- Reallocate and copy any arrays ---- */ + // kills: Note that this array is allocated if and only if MortFlags.summary. + if(src->max_age > 1 && src->use_me && MortFlags.summary){ + Mem_Free(dest->kills); + dest->kills = (IntUS*) Mem_Calloc(src->max_age, sizeof(IntUS), "copy_species: kills"); + for(i = 0; i < src->max_age; ++i){ + dest->kills[i] = src->kills[i]; + } + } + // seedprod + Mem_Free(dest->seedprod); + dest->seedprod = (IntUS*) Mem_Calloc(src->viable_yrs, sizeof(IntUS), "copy_species: seedprod"); + for(i = 0; i < src->viable_yrs; ++i){ + dest->seedprod[i] = src->seedprod[i]; + } + + /* ----------- Copy all fields ----------- */ + dest->allow_growth = src->allow_growth; + dest->alpha = src->alpha; + dest->ann_mort_prob = src->ann_mort_prob; + dest->beta = src->beta; + dest->cohort_surv = src->cohort_surv; + dest->disturbclass = src->disturbclass; + dest->est_count = src->est_count; + dest->estabs = src->estabs; + dest->exp_decay = src->exp_decay; + dest->extragrowth = src->extragrowth; + dest->intrin_rate = src->intrin_rate; + dest->isclonal = src->isclonal; + dest->lastyear_relsize = src->lastyear_relsize; + dest->mature_biomass = src->mature_biomass; + dest->max_age = src->max_age; + dest->max_rate = src->max_rate; + dest->max_seed_estab = src->max_seed_estab; + dest->max_slow = src->max_slow; + dest->max_vegunits = src->max_vegunits; + strcpy(dest->name, src->name); + dest->prob_veggrow[0] = src->prob_veggrow[0]; + dest->prob_veggrow[1] = src->prob_veggrow[1]; + dest->prob_veggrow[2] = src->prob_veggrow[2]; + dest->prob_veggrow[3] = src->prob_veggrow[3]; + dest->pseed = src->pseed; + dest->received_prob = src->received_prob; + dest->relseedlingsize = src->relseedlingsize; + dest->res_grp = src->res_grp; + dest->sd_H = src->sd_H; + dest->sd_Param1 = src->sd_Param1; + dest->sd_Pmax = src->sd_Pmax; + dest->sd_Pmin = src->sd_Pmin; + dest->sd_PPTdry = src->sd_PPTdry; + dest->sd_PPTwet = src->sd_PPTwet; + dest->sd_sgerm = src->sd_sgerm; + dest->sd_VT = src->sd_VT; + dest->seedbank = src->seedbank; + dest->seedling_biomass = src->seedling_biomass; + dest->seedling_estab_prob = src->seedling_estab_prob; + dest->seedling_estab_prob_old = src->seedling_estab_prob_old; + dest->sp_num = src->sp_num; + dest->tempclass = src->tempclass; + dest->use_dispersal = src->use_dispersal; + dest->use_me = src->use_me; + dest->use_temp_response = src->use_temp_response; + dest->var = src->var; + dest->viable_yrs = src->viable_yrs; + + /* ------------- DEEP Copy linked list ---------------- */ + // Destroy the old linked list + destIndv = dest->IndvHead; + while(destIndv){ + next = destIndv->Next; + Mem_Free(destIndv); + destIndv = next; + } + + srcIndv = src->IndvHead; + // If there is a list at all. + if(srcIndv){ + // Allocate a new individual + destIndv = (IndivType*) Mem_Calloc(1, sizeof(IndivType), "copy_species: individual"); + // This individual is the head of the list + dest->IndvHead = destIndv; + // Copy the individual information across + copy_individual(srcIndv, destIndv); + // Since this is the head there is nothing behind it. + destIndv->Prev = NULL; + // While there are more individuals + while(srcIndv->Next){ + // Move to the next individual in src + srcIndv = srcIndv->Next; + // Allocate the next entry in dest. + destIndv->Next = (IndivType*) Mem_Calloc(1, sizeof(IndivType), "copy_species: individual"); + // Doubly link the list before moving on. + destIndv->Next->Prev = destIndv; + // Move to the new entry + destIndv = destIndv->Next; + // copy the individual information across + copy_individual(srcIndv, destIndv); + } + // srcIndv->Next is false: we are at the end of the list. + destIndv->Next = NULL; + } +} + /**************************************************************/ static SpeciesType *_create(void) { @@ -266,7 +383,7 @@ static SpeciesType *_create(void) SpeciesType *p; p = (SpeciesType *) Mem_Calloc(1, sizeof(SpeciesType), "Species_Create"); - p->name = Mem_Calloc(Globals.max_speciesnamelen + 1, sizeof(char), "Species_Create"); + p->name = Mem_Calloc(SuperGlobals.max_speciesnamelen + 1, sizeof(char), "Species_Create"); return (p); @@ -426,10 +543,7 @@ void save_annual_species_relsize() { ForEachSpecies(sp) { if (Species[sp]->max_age == 1) { - //printf("Globals.currYear = %d, sp=%d , Species[sp]->relsize=%.5f ,old value lastyear_relsize : %.5f \n", Globals.currYear, sp, Species[sp]->relsize, Species[sp]->lastyear_relsize); Species[sp]->lastyear_relsize = getSpeciesRelsize(sp); - //Species[sp]->lastyear_relsize = 2; - //printf("Globals.currYear = %d, sp=%d new updated value lastyear_relsize : %.5f \n", Globals.currYear, sp, Species[sp]->lastyear_relsize); } } } diff --git a/ST_sql.c b/ST_sql.c index 6ebfee83..48c0dcbb 100644 --- a/ST_sql.c +++ b/ST_sql.c @@ -109,7 +109,7 @@ static void finalizeStatements() { } void insertIndivKill(int IndivID, int KillTypeID) { - sqlite3_bind_int(stmt_IndivKill, 1, Globals.currYear); + sqlite3_bind_int(stmt_IndivKill, 1, Globals->currYear); sqlite3_bind_int(stmt_IndivKill, 2, KillTypeID); sqlite3_bind_int(stmt_IndivKill, 3, IndivID); @@ -142,7 +142,7 @@ static void insertIndivYearInfoRow(int Year, int IndivID, int MortalityTypeID, i void insertIndivYearInfo(IndivType *ind) { //Take off of age because this happens after rgroup_IncrAges remove if you put before. - insertIndivYearInfoRow(Globals.currYear, ind->id, ind->killedby, (ind->age - 1), ind->mm_extra_res, ind->slow_yrs, ind->yrs_neg_pr, ind->killed, ind->relsize, ind->grp_res_prop, ind->res_required, ind->res_avail, ind->res_extra, ind->pr, ind->growthrate, ind->prob_veggrow); + insertIndivYearInfoRow(Globals->currYear, ind->id, ind->killedby, (ind->age - 1), ind->mm_extra_res, ind->slow_yrs, ind->yrs_neg_pr, ind->killed, ind->relsize, ind->grp_res_prop, ind->res_required, ind->res_avail, ind->res_extra, ind->pr, ind->growthrate, ind->prob_veggrow); } static void insertIndivRow(int IndivID, int Iteration, int CreatedYear, int SpeciesID, int RGroupID) { @@ -157,7 +157,7 @@ static void insertIndivRow(int IndivID, int Iteration, int CreatedYear, int Spec } void insertIndiv(IndivType *ind) { - insertIndivRow(ind->id, Globals.currIter, Globals.currYear, ind->myspecies+1, Species[ind->myspecies]->res_grp+1); + insertIndivRow(ind->id, Globals->currIter, Globals->currYear, ind->myspecies+1, Species[ind->myspecies]->res_grp+1); } static void insertSpeciesYearInfoRow(int Year, int Iteration, int SpeciesID, int EstabCount, int Estabs, float RelSize, float ExtraGrowth, float ReceivedProb, int AllowGrowth, int sdSGerm) { @@ -179,7 +179,7 @@ static void insertSpeciesYearInfoRow(int Year, int Iteration, int SpeciesID, int void insertSpecieYearInfo(SppIndex s) { SpeciesType *sp = Species[s]; - insertSpeciesYearInfoRow(Globals.currYear, Globals.currIter, s+1, sp->est_count, sp->estabs, getSpeciesRelsize(s), sp->extragrowth, sp->received_prob, sp->allow_growth, sp->sd_sgerm); + insertSpeciesYearInfoRow(Globals->currYear, Globals->currIter, s+1, sp->est_count, sp->estabs, getSpeciesRelsize(s), sp->extragrowth, sp->received_prob, sp->allow_growth, sp->sd_sgerm); } static void insertRGroupYearInfoRow(int Year, int Iteration, int RGroupID, int Estabs, int KillYr, int YrsNegPR, float mmExtraRes, float ResRequired, float ResAvail, float ResExtra, float PR, float RelSize, int EstSppCount, int Extirpated, int RegenOk) { @@ -206,7 +206,7 @@ static void insertRGroupYearInfoRow(int Year, int Iteration, int RGroupID, int E void insertRGroupYearInfo(GrpIndex g) { GroupType *rg = RGroup[g]; - insertRGroupYearInfoRow(Globals.currYear, Globals.currIter, g+1, rg->estabs, rg->killyr, rg->yrs_neg_pr, rg->mm_extra_res, rg->res_required, rg->res_avail, rg->res_extra, rg->pr, getRGroupRelsize(g), rg->est_count, rg->extirpated, rg->regen_ok); + insertRGroupYearInfoRow(Globals->currYear, Globals->currIter, g+1, rg->estabs, rg->killyr, rg->yrs_neg_pr, rg->mm_extra_res, rg->res_required, rg->res_avail, rg->res_extra, rg->pr, getRGroupRelsize(g), rg->est_count, rg->extirpated, rg->regen_ok); } static void insertRgroups(void) { @@ -267,8 +267,8 @@ static void insertInfo(void) { beginTransaction(); sprintf(sql, "INSERT INTO info (Years, Iterations, Seed, RGroups, Species, PlotSize) VALUES (%d, %d, %d, %d, %d, %f);", - Globals.runModelYears, Globals.runModelIterations, (int) Globals.randseed, - Globals.grpCount, Globals.sppCount, Globals.plotsize); + SuperGlobals.runModelYears, SuperGlobals.runModelIterations, (int) SuperGlobals.randseed, + Globals->grpCount, Globals->sppCount, Globals->plotsize); rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); sqlcheck(rc, zErrMsg); endTransaction(); diff --git a/ST_stats.c b/ST_stats.c index 866859d3..5145c113 100644 --- a/ST_stats.c +++ b/ST_stats.c @@ -8,8 +8,12 @@ // History: // (6/15/2000) -- INITIAL CODING - cwb // 1/9/01 - revised to make extensive use of malloc() */ -// 5/28/2013 (DLM) - added module level variable accumulators (grid_Stat) for the grid and functions to deal with them (stat_Load_Accumulators(), stat_Save_Accumulators() stat_Free_Accumulators(), and stat_Init_Accumulators()). These functions are called from ST_grid.c and manage the output accumulators so that the gridded version can output correctly. The accumulators are dynamically allocated, so be careful with them. +// 5/28/2013 (DLM) - added module level variable accumulators (grid_Stat) for the grid and functions. // 07/30/2016 (AKT) Fixed bug at std_dev calculation +// 8/30/2019 (Chandler Haukap) - Removed grid_Stat accumulators and functionality. +// Gridded mode accumulators are now stored in the Celltype struct in +// ST_grid.h and swapped into this module using a call to +// stat_Copy_Accumulators(). // /********************************************************/ /********************************************************/ @@ -18,105 +22,27 @@ /* INCLUDES / DEFINES */ /* --------------------------------------------------- */ -#include #include #include #include "ST_steppe.h" #include "filefuncs.h" #include "myMemory.h" -#include "sw_src/SW_Site.h" #include "ST_structs.h" -#include "sxw.h" - extern SXW_t SXW; - extern SW_SITE SW_Site; - -/************ External Variable Declarations ***************/ -/***********************************************************/ +#include "ST_stats.h" // Contains most of the function declarations. +#include "ST_seedDispersal.h" #include "ST_globals.h" -/******** Modular External Function Declarations ***********/ -/* -- truly global functions are declared in functions.h --*/ -/***********************************************************/ - - -/*------------------------------------------------------*/ -/* Modular functions only used on one or two specific */ -/* places; that is, they are not generally useful */ -/* (like C++ friend functions) but have to be declared. */ - void stat_Collect( Int year ) ; - void stat_Collect_GMort ( void ) ; - void stat_Collect_SMort ( void ) ; - void stat_Output_YrMorts( void ) ; - void stat_Output_AllMorts( void) ; - void stat_Output_AllBmass(void) ; - - //Adding below two functions for creating grid cells avg values output file - void stat_Output_AllBmassAvg(void); - void stat_Output_AllCellAvgBmass(const char * filename); - void stat_Output_Seed_Dispersal(const char * filename, const char sep, Bool makeHeader); - void stat_free_mem( void ); - - void stat_Load_Accumulators( int cell, int year ); //these accumulators were added to use in the gridded option... there overall purpose is to save/load data to allow steppe to output correctly when running multiple grid cells - void stat_Save_Accumulators( int cell, int year ); - void stat_Free_Accumulators( void ); - void stat_Init_Accumulators( void ); - -/************************ Local Structure Defs *************/ -/***********************************************************/ -struct accumulators_st { - double ave, sum_dif_sqr, sd; - unsigned long nobs; -}; - -struct stat_st { - char *name; /* array of ptrs to names in RGroup & Species */ - struct accumulators_st *s; -} _Dist, _Ppt, _Temp, +/* ----------------- Local Variables --------------------- */ +StatType *_Dist, *_Ppt, *_Temp, *_Grp, *_Gsize, *_Gpr, *_Gmort, *_Gestab, *_Spp, *_Indv, *_Smort, *_Sestab, *_Sreceived; -typedef struct { - struct accumulators_st *dist, *temp, *ppt, **grp1, **gsize, **gpr2, **gwf2, **gpf2, - **gmort, **gestab, **spp, **indv, **smort, **sestab, **sreceived; -} accumulators_grid_st; - -accumulators_grid_st *grid_Stat; - -struct fire_st { - int *wildfire; - int **prescribedFire; -} *_Gwf; - - -// Local Structure for holding sum values of all the grid cells - -struct accumulators_grid_cell_st { - double sum, sum_std; - unsigned long nobs; -}; - -struct stat_grid_cell_st { - char *name; /* array of ptrs to names in RGroup & Species */ - struct accumulators_grid_cell_st *s; /* array of holding all the years values */ -} _Dist_grid_cell, _Ppt_grid_cell, _Temp_grid_cell, - *_Grp_grid_cell, *_Gsize_grid_cell, *_Gpr_grid_cell,*_Gwf_grid_cell,*_Gpf_grid_cell, *_Gmort_grid_cell, *_Gestab_grid_cell, - *_Spp_grid_cell, *_Indv_grid_cell, *_Smort_grid_cell, *_Sestab_grid_cell, *_Sreceived_grid_cell; - - - +FireStatsType *_Gwf; /*************** Local Function Declarations ***************/ -/***********************************************************/ static void _init( void); static RealF _get_avg( struct accumulators_st *p); static RealF _get_std( struct accumulators_st *p); -//Adding below three functions for copying grid cell values,calculating avg and SD,these values will be used in grid cells avg output file -static void copyStruct(RealF val,RealF std_val,struct accumulators_grid_cell_st *p ); -static RealF _get_gridcell_avg( struct accumulators_grid_cell_st *p); -static int _get_gridcell_sum( struct accumulators_grid_cell_st *p); -static RealF _get_gridcell_std( struct accumulators_grid_cell_st *p); -static void _make_header( char *buf); -static void _make_header_with_std( char *buf); /* I'm making this a macro because it gets called a lot, but * note that the syntax checker is obviated, so make sure @@ -164,14 +90,14 @@ void stat_Collect( Int year ) { } year--; - if (BmassFlags.dist && Plot.disturbed) - _Dist.s[year].nobs++; + if (BmassFlags.dist && Plot->disturbed) + _Dist->s[year].nobs++; if (BmassFlags.ppt) - _collect_add( &_Ppt.s[year], Env.ppt); + _collect_add( &_Ppt->s[year], Env->ppt); if (BmassFlags.tmp) - _collect_add( &_Temp.s[year], Env.temp); + _collect_add( &_Temp->s[year], Env->temp); if (BmassFlags.grpb) { if (BmassFlags.wildfire) { @@ -227,133 +153,57 @@ static void _init( void) { SppIndex sp; GrpIndex rg; -// Memory allocation for local structures that will hold grid cells values for calculating avg - if (UseGrid) - { - - if (BmassFlags.dist) - _Dist_grid_cell.s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, - sizeof(struct accumulators_grid_cell_st), - "_stat_init(Dist)"); - if (BmassFlags.ppt) - _Ppt_grid_cell.s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, - sizeof(struct accumulators_grid_cell_st), - "_stat_init(PPT)"); - if (BmassFlags.tmp) - _Temp_grid_cell.s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, - sizeof(struct accumulators_grid_cell_st), - "_stat_init(Temp)"); - - if (BmassFlags.grpb) - { - _Grp_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.grpCount, sizeof(struct stat_grid_cell_st), "_stat_init(Grp)"); - ForEachGroup(rg) - _Grp_grid_cell[rg].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(Grp[rg].s)"); - - if (BmassFlags.size) - { - _Gsize_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.grpCount, sizeof(struct stat_grid_cell_st), "_stat_init(GSize)"); - ForEachGroup(rg) - _Gsize_grid_cell[rg].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(GSize[rg].s)"); - } - if (BmassFlags.pr) - { - _Gpr_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.grpCount, sizeof(struct stat_grid_cell_st), "_stat_init(Gpr)"); - ForEachGroup(rg) - _Gpr_grid_cell[rg].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(Gpr[rg].s)"); - } - if (BmassFlags.wildfire) - { - _Gpr_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.grpCount, sizeof(struct stat_grid_cell_st), "_stat_init(Gwf)"); - ForEachGroup(rg) - _Gpr_grid_cell[rg].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(Gwf[rg].s)"); - } - if (BmassFlags.prescribedfire) - { - _Gpr_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.grpCount, sizeof(struct stat_grid_cell_st), "_stat_init(Gpf)"); - ForEachGroup(rg) - _Gpr_grid_cell[rg].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(Gpf[rg].s)"); - } - } - - if (BmassFlags.sppb) - { - _Spp_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.sppCount, sizeof(struct stat_grid_cell_st), "_stat_init(Spp)"); - ForEachSpecies(sp) - _Spp_grid_cell[sp].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(Spp[sp].s)"); - - if (BmassFlags.indv) - { - _Indv_grid_cell = (struct stat_grid_cell_st *) - Mem_Calloc( Globals.sppCount, sizeof(struct stat_grid_cell_st), "_stat_init(Indv)"); - ForEachSpecies(sp) - _Indv_grid_cell[sp].s = (struct accumulators_grid_cell_st *) - Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_grid_cell_st), "_stat_init(Indv[sp].s)"); - } - } - - } - - if (BmassFlags.dist) - _Dist.s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + if (BmassFlags.dist) { + _Dist = (StatType*) Mem_Calloc(1, sizeof(StatType), "_stat_init(Dist)"); + _Dist->s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Dist)"); - if (BmassFlags.ppt) - _Ppt.s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + } + if (BmassFlags.ppt) { + _Ppt = (StatType*) Mem_Calloc(1, sizeof(StatType), "_stat_init(PPT"); + _Ppt->s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(PPT)"); - if (BmassFlags.tmp) - _Temp.s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + } + if (BmassFlags.tmp) { + _Temp = (StatType*) Mem_Calloc(1, sizeof(StatType), "_stat_init(Temp)"); + _Temp->s = (struct accumulators_st *) + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Temp)"); + } if (BmassFlags.grpb) { _Grp = (struct stat_st *) - Mem_Calloc( Globals.grpCount, + Mem_Calloc( Globals->grpCount, sizeof(struct stat_st), "_stat_init(Grp)"); ForEachGroup(rg) _Grp[rg].s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Grp[rg].s)"); if (BmassFlags.size) { _Gsize = (struct stat_st *) - Mem_Calloc( Globals.grpCount, + Mem_Calloc( Globals->grpCount, sizeof(struct stat_st), "_stat_init(GSize)"); ForEachGroup(rg) _Gsize[rg].s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(GSize[rg].s)"); } if (BmassFlags.pr) { _Gpr = (struct stat_st *) - Mem_Calloc( Globals.grpCount, + Mem_Calloc( Globals->grpCount, sizeof(struct stat_st), "_stat_init(Gpr)"); ForEachGroup(rg) _Gpr[rg].s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Gpr[rg].s)"); } @@ -366,18 +216,18 @@ static void _init( void) { _Gwf->wildfire = (int *) Mem_Calloc( 1, - sizeof(int) * Globals.runModelYears, + sizeof(int) * SuperGlobals.runModelYears, "_stat_init(Gwf->wildfire)"); _Gwf->prescribedFire = (int **) Mem_Calloc( 1, - sizeof(int **) * Globals.max_rgroups, + sizeof(int **) * SuperGlobals.max_rgroups, "_stat_init(Gwf->prescribedfire"); ForEachGroup(rg){ _Gwf->prescribedFire[rg] = (int *) - Mem_Calloc( Globals.runModelYears, - sizeof(int) * Globals.runModelYears, + Mem_Calloc( SuperGlobals.runModelYears, + sizeof(int) * SuperGlobals.runModelYears, "_stat_init(Gwf->prescribedFire)"); } } @@ -386,7 +236,7 @@ static void _init( void) { if (MortFlags.group) { _Gestab = (struct stat_st *) - Mem_Calloc( Globals.grpCount, + Mem_Calloc( Globals->grpCount, sizeof(struct stat_st), "_stat_init(Gestab)"); ForEachGroup(rg) @@ -395,7 +245,7 @@ static void _init( void) { "_stat_init(Gestab[rg].s)"); _Gmort = (struct stat_st *) - Mem_Calloc( Globals.grpCount, + Mem_Calloc( Globals->grpCount, sizeof(struct stat_st), "_stat_init(Gmort)"); ForEachGroup(rg) @@ -407,30 +257,30 @@ static void _init( void) { if (BmassFlags.sppb) { _Spp = (struct stat_st *) - Mem_Calloc( Globals.sppCount, + Mem_Calloc( Globals->sppCount, sizeof(struct stat_st), "_stat_init(Spp)"); ForEachSpecies(sp) _Spp[sp].s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Spp[sp].s)"); if (BmassFlags.indv) { _Indv = (struct stat_st *) - Mem_Calloc( Globals.sppCount, + Mem_Calloc( Globals->sppCount, sizeof(struct stat_st), "_stat_init(Indv)"); ForEachSpecies(sp) _Indv[sp].s = (struct accumulators_st *) - Mem_Calloc( Globals.runModelYears, + Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Indv[sp].s)"); } } if (MortFlags.species) { _Sestab = (struct stat_st *) - Mem_Calloc( Globals.sppCount, + Mem_Calloc( Globals->sppCount, sizeof(struct stat_st), "_stat_init(Sestab)"); ForEachSpecies(sp) @@ -439,7 +289,7 @@ static void _init( void) { "_stat_init(Sestab[sp].s)"); _Smort = (struct stat_st *) - Mem_Calloc( Globals.sppCount, + Mem_Calloc( Globals->sppCount, sizeof(struct stat_st), "_stat_init(Smort)"); ForEachSpecies(sp) @@ -450,9 +300,9 @@ static void _init( void) { } if (UseSeedDispersal && UseGrid) { - _Sreceived = Mem_Calloc( Globals.sppCount, sizeof(struct stat_st), "_stat_init(Sreceived)"); + _Sreceived = Mem_Calloc( Globals->sppCount, sizeof(struct stat_st), "_stat_init(Sreceived)"); ForEachSpecies(sp) { - _Sreceived[sp].s = (struct accumulators_st *)Mem_Calloc( Globals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Sreceived[sp].s)"); + _Sreceived[sp].s = (struct accumulators_st *)Mem_Calloc( SuperGlobals.runModelYears, sizeof(struct accumulators_st), "_stat_init(Sreceived[sp].s)"); _Sreceived[sp].name = &Species[sp]->name[0]; } } @@ -476,251 +326,28 @@ static void _init( void) { } } -/***********************************************************/ -void stat_Init_Accumulators( void ) { - //allocates memory for all of the grid accumulators - grid_Stat = Mem_Calloc(Globals.nCells, sizeof(accumulators_grid_st), "stat_Init_Accumulators()"); - - int i, j; - for( i = 0; i < Globals.nCells; i++) { - if (BmassFlags.dist) grid_Stat[i].dist = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.ppt) grid_Stat[i].ppt = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.tmp) grid_Stat[i].temp = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - - if (BmassFlags.grpb) { - grid_Stat[i].grp1 = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); // gave grp and gpr numbers attached to them so I wouldn't mix them up lol... bad (confusing) variable names on part of the original creator. - if (BmassFlags.size) grid_Stat[i].gsize = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.pr) grid_Stat[i].gpr2 = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - if (BmassFlags.wildfire) grid_Stat[i].gwf2 = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - if (BmassFlags.prescribedfire) grid_Stat[i].gpf2 = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - } - if (MortFlags.group) { - grid_Stat[i].gmort = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - grid_Stat[i].gestab = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - GrpIndex gp; - ForEachGroup(gp) { - grid_Stat[i].gmort[gp] = Mem_Calloc(GrpMaxAge(gp), sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - grid_Stat[i].gestab[gp] = Mem_Calloc(1, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - } - } - if(BmassFlags.sppb) { - grid_Stat[i].spp = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - if(BmassFlags.indv) grid_Stat[i].indv = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - } - if (MortFlags.species) { - grid_Stat[i].smort = Mem_Calloc(Globals.sppCount, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - grid_Stat[i].sestab = Mem_Calloc(Globals.sppCount, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - SppIndex sp; - ForEachSpecies(sp) { - grid_Stat[i].smort[sp] = Mem_Calloc(SppMaxAge(sp), sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - grid_Stat[i].sestab[sp] = Mem_Calloc(1, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - } - } - - if(UseSeedDispersal && UseGrid) - grid_Stat[i].sreceived = Mem_Calloc(Globals.runModelYears, sizeof(struct accumulators_st*), "stat_Init_Accumulators()"); - - - for( j = 0; j < Globals.runModelYears; j++) { - if (BmassFlags.grpb) { - grid_Stat[i].grp1[j] = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.size) grid_Stat[i].gsize[j] = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.pr) grid_Stat[i].gpr2[j] = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.wildfire) grid_Stat[i].gwf2[j] = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if (BmassFlags.prescribedfire) grid_Stat[i].gpf2[j] = Mem_Calloc(Globals.grpCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - } - if(BmassFlags.sppb) { - grid_Stat[i].spp[j] = Mem_Calloc(Globals.sppCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - if(BmassFlags.indv) grid_Stat[i].indv[j] = Mem_Calloc(Globals.sppCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - } - if(UseSeedDispersal && UseGrid) - grid_Stat[i].sreceived[j] = Mem_Calloc(Globals.sppCount, sizeof(struct accumulators_st), "stat_Init_Accumulators()"); - } - } -} - -/***********************************************************/ -void stat_Load_Accumulators(int cell, int year) { - //loads the accumulators for the cell at the given year - - if (firsttime) { - firsttime = FALSE; - _init(); - } - IntS age; - int yr; - yr = year - 1; - - if(MortFlags.species) { - SppIndex sp; - - ForEachSpecies(sp) { - if ( !Species[sp]->use_me) continue; - _copy_over(&_Sestab[sp].s[0], &grid_Stat[cell].sestab[sp][0]); - IntS age; - for (age=0; age < SppMaxAge(sp); age++) - _copy_over(&_Smort[sp].s[age], &grid_Stat[cell].smort[sp][age]); - } - } - if(MortFlags.group) { - GrpIndex rg; - - ForEachGroup(rg) { - if (!RGroup[rg]->use_me) continue; - _copy_over(&_Gestab[rg].s[0], &grid_Stat[cell].gestab[rg][0]); - for (age=0; age < GrpMaxAge(rg); age++) - _copy_over(&_Gmort[rg].s[age], &grid_Stat[cell].gmort[rg][age]); - } - } - - if (BmassFlags.tmp) _copy_over(&_Temp.s[yr], &grid_Stat[cell].temp[yr]); - if (BmassFlags.ppt) _copy_over(&_Ppt.s[yr], &grid_Stat[cell].ppt[yr]); - if (BmassFlags.dist) _copy_over(&_Dist.s[yr], &grid_Stat[cell].dist[yr]); - - if(BmassFlags.grpb) { - GrpIndex c; - ForEachGroup(c) { - _copy_over(&_Grp[c].s[yr], &grid_Stat[cell].grp1[yr][c]); - if (BmassFlags.size) _copy_over(&_Gsize[c].s[yr], &grid_Stat[cell].gsize[yr][c]); - if (BmassFlags.pr) _copy_over(&_Gpr[c].s[yr], &grid_Stat[cell].gpr2[yr][c]); - } - } - - if(BmassFlags.sppb) { - SppIndex s; - ForEachSpecies(s) { - _copy_over(&_Spp[s].s[yr], &grid_Stat[cell].spp[yr][s]); - if (BmassFlags.indv) _copy_over(&_Indv[s].s[yr], &grid_Stat[cell].indv[yr][s]); - } - } - - if(UseGrid && UseSeedDispersal) { - SppIndex s; - ForEachSpecies(s) - _copy_over(&_Sreceived[s].s[yr], &grid_Stat[cell].sreceived[yr][s]); - } -} - -/***********************************************************/ -void stat_Save_Accumulators(int cell, int year) { - //saves the accumulators for the cell at the given year - - if (firsttime) { - firsttime = FALSE; - _init(); - } - IntS age; - int yr; - yr = year - 1; - - if(MortFlags.species) { - SppIndex sp; - - ForEachSpecies(sp) { - if ( !Species[sp]->use_me) continue; - _copy_over(&grid_Stat[cell].sestab[sp][0], &_Sestab[sp].s[0]); - for (age=0; age < SppMaxAge(sp); age++) - _copy_over(&grid_Stat[cell].smort[sp][age], &_Smort[sp].s[age]); - } - } - if(MortFlags.group) { - GrpIndex rg; - - ForEachGroup(rg) { - if (!RGroup[rg]->use_me) continue; - _copy_over(&grid_Stat[cell].gestab[rg][0], &_Gestab[rg].s[0]); - for (age=0; age < GrpMaxAge(rg); age++) - _copy_over(&grid_Stat[cell].gmort[rg][age], &_Gmort[rg].s[age]); - } - } - - if (BmassFlags.tmp) _copy_over(&grid_Stat[cell].temp[yr], &_Temp.s[yr]); - if (BmassFlags.ppt) _copy_over(&grid_Stat[cell].ppt[yr], &_Ppt.s[yr]); - if (BmassFlags.dist) _copy_over(&grid_Stat[cell].dist[yr], &_Dist.s[yr]); - - if(BmassFlags.grpb) { - GrpIndex c; - ForEachGroup(c) { - _copy_over(&grid_Stat[cell].grp1[yr][c], &_Grp[c].s[yr]); - if (BmassFlags.size) _copy_over(&grid_Stat[cell].gsize[yr][c], &_Gsize[c].s[yr]); - if (BmassFlags.pr) _copy_over(&grid_Stat[cell].gpr2[yr][c], &_Gpr[c].s[yr]); - } - } - - if(BmassFlags.sppb) { - SppIndex s; - ForEachSpecies(s) { - _copy_over(&grid_Stat[cell].spp[yr][s], &_Spp[s].s[yr]); - if (BmassFlags.indv) _copy_over(&grid_Stat[cell].indv[yr][s], &_Indv[s].s[yr]); - } - } - - if(UseGrid && UseSeedDispersal) { - SppIndex s; - ForEachSpecies(s) - _copy_over(&grid_Stat[cell].sreceived[yr][s], &_Sreceived[s].s[yr]); - } - -} - -/***********************************************************/ -void stat_Free_Accumulators( void ) { - //frees all the memory allocated in stat_init_Accumulators() - - int i, j; - for( i = 0; i < Globals.nCells; i++) { - for( j = 0; j < Globals.runModelYears; j++) { - if(BmassFlags.grpb) { - Mem_Free(grid_Stat[i].grp1[j]); - if (BmassFlags.size) Mem_Free(grid_Stat[i].gsize[j]); - if (BmassFlags.pr) Mem_Free(grid_Stat[i].gpr2[j]); - if (BmassFlags.wildfire) Mem_Free(grid_Stat[i].gwf2[j]); - if (BmassFlags.prescribedfire) Mem_Free(grid_Stat[i].gpf2[j]); - } - if(BmassFlags.sppb) { - Mem_Free(grid_Stat[i].spp[j]); - if(BmassFlags.indv) Mem_Free(grid_Stat[i].indv[j]); - } - if(UseSeedDispersal && UseGrid) - Mem_Free(grid_Stat[i].sreceived[j]); - } - - if (BmassFlags.dist) Mem_Free(grid_Stat[i].dist); - if (BmassFlags.ppt) Mem_Free(grid_Stat[i].ppt); - if (BmassFlags.tmp) Mem_Free(grid_Stat[i].temp); - - if(BmassFlags.grpb) { - Mem_Free(grid_Stat[i].grp1);// gave grp and gpr numbers attached to them so I wouldn't mix them up lol... bad (confusing) variable names on part of the original creator. - if (BmassFlags.size) Mem_Free(grid_Stat[i].gsize); - if (BmassFlags.size) Mem_Free(grid_Stat[i].gpr2); - } - if (MortFlags.group) { - GrpIndex gp; - ForEachGroup(gp) { - Mem_Free(grid_Stat[i].gmort[gp]); - Mem_Free(grid_Stat[i].gestab[gp]); - } - Mem_Free(grid_Stat[i].gmort); - Mem_Free(grid_Stat[i].gestab); - } - if(BmassFlags.sppb) { - Mem_Free(grid_Stat[i].spp); - if(BmassFlags.indv) Mem_Free(grid_Stat[i].indv); - } - if (MortFlags.species) { - SppIndex sp; - ForEachSpecies(sp) { - Mem_Free(grid_Stat[i].smort[sp]); - Mem_Free(grid_Stat[i].sestab[sp]); - } - Mem_Free(grid_Stat[i].smort); - Mem_Free(grid_Stat[i].sestab); - } - if(UseSeedDispersal && UseGrid) - Mem_Free(grid_Stat[i].sreceived); - } - Mem_Free(grid_Stat); - stat_free_mem(); +/* Shallow copies StatType and FireStatsType pointers to the local pointers. + This is intended to be used with gridded mode to load in a given cell */ +void stat_Copy_Accumulators(StatType* newDist, StatType* newPpt, StatType* newTemp, StatType* newGrp, StatType* newGsize, + StatType* newGpr, StatType* newGmort, StatType* newGestab, StatType* newSpp, StatType* newIndv, + StatType* newSmort, StatType* newSestab, StatType* newSrecieved, FireStatsType* newGwf, Bool firstTime){ + + /* Move the local pointers to the location of the given pointers */ + _Dist = newDist; + _Ppt = newPpt; + _Temp = newTemp; + _Grp = newGrp; + _Gsize = newGsize; + _Gpr = newGpr; + _Gmort = newGmort; + _Gestab = newGestab; + _Spp = newSpp; + _Indv = newIndv; + _Smort = newSmort; + _Sestab = newSestab; + _Sreceived = newSrecieved; + _Gwf = newGwf; + firsttime = firstTime; } /***********************************************************/ @@ -749,9 +376,18 @@ void stat_free_mem( void ) { Mem_Free(_Gwf->prescribedFire); } - if (BmassFlags.dist) Mem_Free(_Dist.s); - if (BmassFlags.ppt) Mem_Free(_Ppt.s); - if (BmassFlags.tmp) Mem_Free(_Temp.s); + if (BmassFlags.dist) { + Mem_Free(_Dist->s); + Mem_Free(_Dist); + } + if (BmassFlags.ppt) { + Mem_Free(_Ppt->s); + Mem_Free(_Ppt); + } + if (BmassFlags.tmp) { + Mem_Free(_Temp->s); + Mem_Free(_Temp); + } if(BmassFlags.grpb) { Mem_Free(_Grp); @@ -836,7 +472,7 @@ void stat_Collect_SMort ( void ) { /***********************************************************/ void stat_Output_YrMorts( void ) { - FILE *f = Globals.mort.fp_year; + FILE *f = Globals->mort.fp_year; IntS age; GrpIndex rg; SppIndex sp; @@ -867,7 +503,7 @@ void stat_Output_YrMorts( void ) { fprintf(f,"\n"); /* print one line of kill frequencies per age */ - for(age=0; age < Globals.Max_Age; age++) { + for(age=0; age < Globals->Max_Age; age++) { fprintf(f,"%d", age+1); if (MortFlags.group) { ForEachGroup(rg){ @@ -927,7 +563,7 @@ void stat_Output_AllMorts( void) { fprintf(f,"\n"); /* print one line of kill frequencies per age */ - for(age=0; age < Globals.Max_Age; age++) { + for(age=0; age < Globals->Max_Age; age++) { fprintf(f,"%d", age+1); if (MortFlags.group) { ForEachGroup(rg) @@ -948,247 +584,6 @@ void stat_Output_AllMorts( void) { CloseFile(&f); } - -//This function will create individual grid cell output file and copy values to calculate for calculating grid cell avg values -/***********************************************************/ -void stat_Output_AllBmassAvg() { - char buf[1024], tbuf[80], sep = BmassFlags.sep; - IntS yr; - GrpIndex rg; - SppIndex sp; - FILE *f; - - if (!BmassFlags.summary) return; - - f = OpenFile( Parm_name( F_BMassAvg), "w"); - - buf[0]='\0'; - - if (BmassFlags.header) { - _make_header(buf); - fprintf(f, "%s", buf); - } - - for( yr=1; yr<= Globals.runModelYears; yr++) { - *buf = '\0'; - if (BmassFlags.yr) - sprintf(buf, "%d%c", yr, sep); - - if (BmassFlags.dist) { - sprintf(tbuf, "%ld%c", _Dist.s[yr-1].nobs, sep); - _Dist_grid_cell.s[yr-1].nobs = _Dist.s[yr-1].nobs; - strcat(buf, tbuf); - } - - if (BmassFlags.ppt) - { - RealF avg = _get_avg(&_Ppt.s[yr - 1]); - RealF std = _get_std(&_Ppt.s[yr - 1]); - sprintf(tbuf, "%f%c%f%c", avg, sep, std, sep); - copyStruct(avg, std, &_Ppt_grid_cell.s[yr - 1]); - strcat(buf, tbuf); - } - - if (BmassFlags.pclass) - { - sprintf(tbuf, "\"NA\"%c", sep); - strcat(buf, tbuf); - } - - if (BmassFlags.tmp) - { - RealF avg = _get_avg(&_Temp.s[yr - 1]); - RealF std = _get_std(&_Temp.s[yr - 1]); - sprintf(tbuf, "%f%c%f%c", avg, sep, std, sep); - copyStruct(avg,std, &_Temp_grid_cell.s[yr - 1]); - strcat(buf, tbuf); - } - - if (BmassFlags.grpb) - { - ForEachGroup(rg) - { - RealF avg = _get_avg(&_Grp[rg].s[yr - 1]); - sprintf(tbuf, "%f%c", avg, sep); - copyStruct(avg,0.0, &_Grp_grid_cell[rg].s[yr - 1]); - strcat(buf, tbuf); - - if (BmassFlags.size) - { - RealF sizeAvg = _get_avg(&_Gsize[rg].s[yr - 1]); - sprintf(tbuf, "%f%c",sizeAvg , sep); - copyStruct(sizeAvg,0.0,&_Gsize_grid_cell[rg].s[yr - 1]); - strcat(buf, tbuf); - } - - if (BmassFlags.pr) - { - RealF prAvg = _get_avg(&_Gpr[rg].s[yr - 1]); - RealF std = _get_std(&_Gpr[rg].s[yr - 1]); - sprintf(tbuf, "%f%c%f%c", prAvg, sep,std , sep); - copyStruct(prAvg,std,&_Gpr_grid_cell[rg].s[yr - 1]); - strcat(buf, tbuf); - } - if (BmassFlags.wildfire) - { - double wfsum = _Gwf->wildfire[yr-1]; - sprintf(tbuf, "%f%c", wfsum, sep); - strcat(buf, tbuf); - } - if (BmassFlags.prescribedfire) - { - double pfsum = _Gwf->prescribedFire[rg][yr-1]; - sprintf(tbuf, "%f%c", pfsum, sep); - strcat(buf, tbuf); - } - } - } - - - if (BmassFlags.sppb) - { - ForEachSpecies(sp) - { - RealF spAvg = _get_avg(&_Spp[sp].s[yr - 1]); - sprintf(tbuf, "%f%c", spAvg, sep); - copyStruct(spAvg,0.0,&_Spp_grid_cell[sp].s[yr - 1]); - strcat(buf, tbuf); - - if (BmassFlags.indv) - { - RealF indvAvg = _get_avg(&_Indv[sp].s[yr - 1]); - sprintf(tbuf, "%f%c", indvAvg, sep); - copyStruct(indvAvg,0.0,&_Indv_grid_cell[sp].s[yr - 1]); - strcat(buf, tbuf); - } - - } - } - - fprintf( f, "%s\n", buf); - } /* end of foreach year */ - CloseFile(&f); - -} - -//This function will create grid cell avg values output file -void stat_Output_AllCellAvgBmass(const char * filename) -{ - - char buf[1024], tbuf[80], sep = BmassFlags.sep; - IntS yr; - GrpIndex rg; - SppIndex sp; - FILE *f; - - if (!BmassFlags.summary) - return; - - f = OpenFile(filename, "w"); - - buf[0] = '\0'; - - if (BmassFlags.header) - { - _make_header(buf); - fprintf(f, "%s", buf); - } - - for (yr = 1; yr <= Globals.runModelYears; yr++) - { - - *buf = '\0'; - if (BmassFlags.yr) - sprintf(buf, "%d%c", yr, sep); - - if (BmassFlags.dist) - { - sprintf(tbuf, "%ld%c", _Dist_grid_cell.s[yr - 1].nobs, sep); - strcat(buf, tbuf); - } - - if (BmassFlags.ppt) - { - sprintf(tbuf, "%f%c%f%c", - _get_gridcell_avg(&_Ppt_grid_cell.s[yr - 1]), sep, - _get_gridcell_std(&_Ppt_grid_cell.s[yr - 1]), sep); - strcat(buf, tbuf); - } - - if (BmassFlags.pclass) - { - sprintf(tbuf, "\"NA\"%c", sep); - strcat(buf, tbuf); - } - - if (BmassFlags.tmp) - { - sprintf(tbuf, "%f%c%f%c", - _get_gridcell_avg(&_Temp_grid_cell.s[yr - 1]), sep, - _get_gridcell_std(&_Temp_grid_cell.s[yr - 1]), sep); - strcat(buf, tbuf); - } - - if (BmassFlags.grpb) - { - ForEachGroup(rg) - { - sprintf(tbuf, "%f%c", _get_gridcell_avg(&_Grp_grid_cell[rg].s[yr - 1]), sep); - strcat(buf, tbuf); - - if (BmassFlags.size) - { - sprintf(tbuf, "%f%c", _get_gridcell_avg(&_Gsize_grid_cell[rg].s[yr - 1]), sep); - strcat(buf, tbuf); - } - - if (BmassFlags.pr) - { - sprintf(tbuf, "%f%c%f%c", - _get_gridcell_avg(&_Gpr_grid_cell[rg].s[yr - 1]), sep, - _get_gridcell_std(&_Gpr_grid_cell[rg].s[yr - 1]), sep); - strcat(buf, tbuf); - } - if (BmassFlags.wildfire) - { - sprintf(tbuf, "%d%c", _get_gridcell_sum(&_Gsize_grid_cell[rg].s[yr - 1]), sep); - strcat(buf, tbuf); - } - if (BmassFlags.prescribedfire) - { - sprintf(tbuf, "%f%c", _get_gridcell_avg(&_Gsize_grid_cell[rg].s[yr - 1]), sep); - strcat(buf, tbuf); - } - } - } - - if (BmassFlags.sppb) - { - ForEachSpecies(sp) - { - sprintf(tbuf, "%f%c",_get_gridcell_avg( &_Spp_grid_cell[sp].s[yr-1]), sep); - strcat( buf, tbuf); - - if (BmassFlags.indv) - { - sprintf(tbuf, "%f%c", _get_gridcell_avg( &_Indv_grid_cell[sp].s[yr-1]), sep); - strcat( buf, tbuf); - } - - } - } - - fprintf(f, "%s\n", buf); - } /* end of foreach year */ - CloseFile(&f); - -} - - - - - - /***********************************************************/ void stat_Output_AllBmass(void) { @@ -1205,25 +600,25 @@ void stat_Output_AllBmass(void) { buf[0]='\0'; if (BmassFlags.header) { - _make_header_with_std(buf); + make_header_with_std(buf); fprintf(f, "%s", buf); } - for( yr=1; yr<= Globals.runModelYears; yr++) { + for( yr=1; yr<= SuperGlobals.runModelYears; yr++) { *buf = '\0'; if (BmassFlags.yr) sprintf(buf, "%d%c", yr, sep); if (BmassFlags.dist) { - sprintf(tbuf, "%ld%c", _Dist.s[yr-1].nobs, + sprintf(tbuf, "%ld%c", _Dist->s[yr-1].nobs, sep); strcat(buf, tbuf); } if (BmassFlags.ppt) { sprintf(tbuf, "%f%c%f%c", - _get_avg(&_Ppt.s[yr-1]), sep, - _get_std(&_Ppt.s[yr-1]), sep); + _get_avg(&_Ppt->s[yr-1]), sep, + _get_std(&_Ppt->s[yr-1]), sep); strcat( buf, tbuf); } @@ -1234,8 +629,8 @@ void stat_Output_AllBmass(void) { if (BmassFlags.tmp) { sprintf(tbuf, "%f%c%f%c", - _get_avg(&_Temp.s[yr-1]), sep, - _get_std(&_Temp.s[yr-1]), sep); + _get_avg(&_Temp->s[yr-1]), sep, + _get_std(&_Temp->s[yr-1]), sep); strcat( buf, tbuf); } @@ -1275,7 +670,7 @@ void stat_Output_AllBmass(void) { if (BmassFlags.sppb) { - for ((sp) = 0; (sp) < Globals.sppCount - 1; (sp)++) + for ((sp) = 0; (sp) < Globals->sppCount - 1; (sp)++) { sprintf(tbuf, "%f%c", _get_avg(&_Spp[sp].s[yr - 1]), sep); strcat(buf, tbuf); @@ -1311,7 +706,7 @@ void stat_Output_AllBmass(void) { /***********************************************************/ -void stat_Output_Seed_Dispersal(const char * filename, const char sep, Bool makeHeader) { +void stat_Output_Seed_Dispersal(const char * filename, const char sep) { //do stuff... char buf[1024], tbuf[80]; IntS yr; @@ -1320,16 +715,16 @@ void stat_Output_Seed_Dispersal(const char * filename, const char sep, Bool make f = OpenFile(filename, "w"); - if(makeHeader) { - fprintf(f,"Year"); - ForEachSpecies(sp) { - fprintf(f, "%c%s_prob", sep, Species[sp]->name); - fprintf(f, "%c%s_std", sep, Species[sp]->name); - } - fprintf(f,"\n"); + /* ---------- Make a header for the file --------- */ + fprintf(f,"Year"); + ForEachSpecies(sp) { + fprintf(f, "%c%s_prob", sep, Species[sp]->name); + fprintf(f, "%c%s_std", sep, Species[sp]->name); } + fprintf(f,"\n"); + /* ------------------ END header ----------------- */ - for( yr=1; yr<= Globals.runModelYears; yr++) { + for( yr=1; yr<= SuperGlobals.runModelYears; yr++) { *buf = '\0'; sprintf(buf, "%d%c", yr, sep); @@ -1357,45 +752,8 @@ static RealF _get_std(struct accumulators_st *p) return p->sd; } - - -static void copyStruct(RealF val,RealF std_val,struct accumulators_grid_cell_st *p) -{ - p->sum = p->sum + val; - p->sum_std = p->sum_std + std_val; -} - -/***********************************************************/ -static RealF _get_gridcell_avg(struct accumulators_grid_cell_st *p) -{ - - if (Globals.nCells == 0) - return 0.0; - RealF avg = (RealF) (p->sum / (double) Globals.nCells); - return avg; -} -static int _get_gridcell_sum(struct accumulators_grid_cell_st *p) -{ - - if (Globals.nCells == 0) - return 0; - int sum = (RealF) (p->sum); - return sum; -} - - -/***********************************************************/ -static RealF _get_gridcell_std(struct accumulators_grid_cell_st *p) -{ - if (Globals.nCells == 0) - return 0.0; - RealF avg = (RealF) (p->sum_std / (double) Globals.nCells); - return avg; -} - - /***********************************************************/ -static void _make_header_with_std( char *buf) { +void make_header_with_std( char *buf) { char **fields; char tbuf[80]; @@ -1403,10 +761,10 @@ static void _make_header_with_std( char *buf) { SppIndex sp; Int i, fc=0; - fields = (char **)Mem_Calloc(MAX_OUTFIELDS * 2, sizeof(char *), "_make_header_with_std"); + fields = (char **)Mem_Calloc(MAX_OUTFIELDS * 2, sizeof(char *), "make_header_with_std"); for (i = 0; i < MAX_OUTFIELDS * 2; i++) { - fields[i] = (char *)Mem_Calloc(MAX_FIELDLEN + 1, sizeof(char), "_make_header_with_std"); + fields[i] = (char *)Mem_Calloc(MAX_FIELDLEN + 1, sizeof(char), "make_header_with_std"); } /* Set up headers */ @@ -1480,7 +838,7 @@ static void _make_header_with_std( char *buf) { } /***********************************************************/ -static void _make_header( char *buf) { +void make_header( char *buf) { char **fields; char tbuf[80]; @@ -1488,10 +846,10 @@ static void _make_header( char *buf) { SppIndex sp; Int i, fc=0; - fields = (char **)Mem_Calloc(MAX_OUTFIELDS * 2, sizeof(char *), "_make_header"); + fields = (char **)Mem_Calloc(MAX_OUTFIELDS * 2, sizeof(char *), "make_header"); for (i = 0; i < MAX_OUTFIELDS * 2; i++) { - fields[i] = (char *)Mem_Calloc(MAX_FIELDLEN + 1, sizeof(char), "_make_header"); + fields[i] = (char *)Mem_Calloc(MAX_FIELDLEN + 1, sizeof(char), "make_header"); } /* Set up headers */ diff --git a/ST_stats.h b/ST_stats.h new file mode 100644 index 00000000..b8d2acbb --- /dev/null +++ b/ST_stats.h @@ -0,0 +1,53 @@ +/* \file ST_stats.h + * \author Chandler Haukap in August 2019 + * + * This file defines all structs used in ST_stats.c. + * It was created to allow the gridded code to instantiate accumulators + * without including ST_stats.c. + * + * To read the documentation related to creating this file see issues + * #259 and #266 on GitHub */ + +#ifndef STATS_STRUCT_DEF +#define STATS_STRUCT_DEF + +#include "ST_defines.h" + +/* Basic struct that holds average, sum of differences squared, standard deviation + * and number of entries. This is enough information to calculate running values without + * storing raw data. If you would like to create a new accumulator do not use this + * struct. Instead, use StatType.*/ +struct accumulators_st { + double ave, sum_dif_sqr, sd; + unsigned long nobs; +}; + +/* Accumulator along with the RGroup or Species name. */ +struct stat_st { + char *name; /* array of ptrs to names in RGroup & Species */ + struct accumulators_st *s; +} typedef StatType; + +/* Struct for wildfire and prescribed fire stats. */ +struct fire_st { + int *wildfire; + int **prescribedFire; +} typedef FireStatsType; + +/*----------------------- Exported Functions ---------------------------------- */ +void stat_Collect( Int year ) ; +void stat_Collect_GMort ( void ) ; +void stat_Collect_SMort ( void ) ; +void stat_Output_YrMorts( void ) ; +void stat_Output_AllMorts( void) ; +void stat_Output_AllBmass(void) ; +void stat_Output_Seed_Dispersal(const char * filename, const char sep); +void stat_free_mem( void ); +void stat_Copy_Accumulators(StatType* newDist, StatType* newPpt, StatType* newTemp, StatType* newGrp, + StatType* newGsize, StatType* newGpr, StatType* newGmort, StatType* newGestab, + StatType* newSpp, StatType* newIndv, StatType* newSmort, StatType* newSestab, + StatType* newSrecieved, FireStatsType* newGwf, Bool firstTime); +void make_header( char *buf); +void make_header_with_std( char *buf); + +#endif \ No newline at end of file diff --git a/ST_structs.h b/ST_structs.h index c1027e08..4d1ca72d 100644 --- a/ST_structs.h +++ b/ST_structs.h @@ -123,13 +123,14 @@ struct species_st { cohort_surv, exp_decay, /* annuals: exponent for viability decay function */ prob_veggrow[4], /* 1 value for each mortality type, if clonal*/ - sd_Param1, /* for seed dispersal */ - sd_PPTdry, - sd_PPTwet, - sd_Pmin, - sd_Pmax, - sd_H, - sd_VT; + sd_Param1, /* for seed dispersal */ + sd_PPTdry, /* for seed dispersal */ + sd_PPTwet, /* for seed dispersal */ + sd_Pmin, /* for seed dispersal */ + sd_Pmax, /* for seed dispersal */ + sd_H, /* for seed dispersal */ + sd_VT, /* for seed dispersal */ + sd_VW; /* for seed dispersal */ TempClass tempclass; DisturbClass disturbclass; Bool isclonal, @@ -284,21 +285,12 @@ struct globals_st { RealF plotsize, /* size of plot in square meters */ gsppt_prop, /* proportion of ppt during growing season*/ tempparm[2][3]; /* three parms for Warm/Cool growth mod*/ - IntUS runModelYears, /* number of years to run the model*/ - Max_Age, /* oldest plant; same as runModelYears for now */ + IntUS Max_Age, /* oldest plant; same as runModelYears for now */ currYear, - runModelIterations, /* run model this many times for statistics */ currIter, grpCount, /* number of groups defined*/ sppCount, /* number of species defined*/ - transp_window, /* Number of years for which transpiration data is kept*/ - nCells; /* number of cells to use in Grid, only applicable if grid function is being used */ - IntL randseed; /* random seed from input file */ - size_t max_rgroups, /* Maximum resource groups allowed. */ - max_groupnamelen, /* Maximum resource group name length. */ - max_spp_per_grp, /* Maximum species allowed per resource group. */ - max_indivs_per_spp, /* Maximum individuals allowed per species. */ - max_speciesnamelen; /* Maximum species name length. */ + transp_window; /* Number of years for which transpiration data is kept*/ struct outfiles_st bmass, mort; }; @@ -331,7 +323,19 @@ struct mortflags_st { char sep; }; +struct superglobals_st { + size_t max_rgroups, /* Maximum resource groups allowed. */ + max_groupnamelen, /* Maximum resource group name length. */ + max_spp_per_grp, /* Maximum species allowed per resource group. */ + max_indivs_per_spp, /* Maximum individuals allowed per species. */ + max_speciesnamelen; /* Maximum species name length. */ + + IntUS runModelIterations, + runInitializationYears, + runModelYears, + nCells; /* number of cells to use in Grid, only applicable if grid function is being used */ - + IntL randseed; +}; #endif diff --git a/makefile b/makefile index 81a9aefc..56fc59ed 100644 --- a/makefile +++ b/makefile @@ -55,8 +55,10 @@ SRCS =\ $(Src)/ST_species.c\ $(Src)/ST_stats.c\ $(Src)/ST_grid.c\ - $(Src)/ST_sql.c - #$(Src)/sxw_tester.c + $(Src)/ST_sql.c\ + $(Src)/ST_initialization.c\ + $(Src)/ST_progressBar.c\ + $(Src)/ST_seedDispersal.c EXOBJS =\ $(oDir)/sqlite-amalgamation/sqlite3.o\ @@ -98,8 +100,10 @@ EXOBJS =\ $(oDir)/ST_stats.o\ $(oDir)/sxw_environs.o\ $(oDir)/ST_grid.o\ - $(oDir)/ST_sql.o - #$(oDir)/sxw_tester.o + $(oDir)/ST_sql.o\ + $(oDir)/ST_initialization.o\ + $(oDir)/ST_progressBar.o\ + $(oDir)/ST_seedDispersal.o ALLOBJS = $(EXOBJS) ALLBIN = $(Bin)/stepwat @@ -349,9 +353,17 @@ $(oDir)/sw_src/SW_VegEstab.o: sw_src/SW_VegEstab.c sw_src/generic.h sw_src/filef sw_src/SW_Model.h sw_src/SW_SoilWater.h sw_src/SW_Weather.h sw_src/SW_VegEstab.h $(CC) $(C_FLAGS) $(CPPFLAGS) $(incDirs) -c -o $@ $< -$(oDir)/ST_grid.o: ST_grid.c ST_steppe.h ST_defines.h sw_src/generic.h \ - ST_globals.h sw_src/myMemory.h ST_globals.h sw_src/pcg/pcg_basic.h +$(oDir)/ST_grid.o: ST_grid.c $(CC) $(C_FLAGS) $(CPPFLAGS) $(incDirs) -c -o $@ $< $(oDir)/ST_sql.o: ST_sql.c ST_steppe.h ST_globals.h $(CC) $(C_FLAGS) $(CPPFLAGS) $(incDirs) -c -o $@ $< + +$(oDir)/ST_initialization.o: ST_initialization.c + $(CC) $(C_FLAGS) $(CPPFLAGS) $(incDirs) -c -o $@ $< + +$(oDir)/ST_progressBar.o: ST_progressBar.c + $(CC) $(C_FLAGS) $(CPPFLAGS) $(incDirs) -c -o $@ $< + +$(oDir)/ST_seedDispersal.o: ST_seedDispersal.c + $(CC) $(C_FLAGS) $(CPPFLAGS) $(incDirs) -c -o $@ $< \ No newline at end of file diff --git a/sw_src b/sw_src index acce170e..9fe0a657 160000 --- a/sw_src +++ b/sw_src @@ -1 +1 @@ -Subproject commit acce170e2680363c1ea1eee2b454265b12490537 +Subproject commit 9fe0a6578515ed69126481dfcf340f525db608c7 diff --git a/sxw.c b/sxw.c index b6b52687..ae5c69d4 100644 --- a/sxw.c +++ b/sxw.c @@ -33,7 +33,10 @@ * defined with double vs single precision and take * appropriate casting measures. * 07-16-12 (DLM) - made a ton of changes to try and - * get it to compile with the new updated version of soilwat (version 23) */ + * get it to compile with the new updated version of soilwat (version 23) + * 11-15-19 - Chandler Haukap - The functionality described by cwb on February + * 28 2002 has been entirely deprecated. I removed the last reference + * to SXW_BYMAXSIZE and _Grp_BMass today. */ /********************************************************/ /********************************************************/ @@ -69,7 +72,7 @@ /*************** Global Variable Declarations ***************/ /***********************************************************/ -SXW_t SXW; +SXW_t* SXW; extern SW_SITE SW_Site; extern SW_MODEL SW_Model; @@ -82,42 +85,16 @@ extern SW_MARKOV SW_Markov; extern Bool prepare_IterationSummary; extern Bool storeAllIterations; - - /*************** Module/Local Variable Declarations ***************/ /***********************************************************/ /* these are initialized and maybe populated here but are used * in sxw_resource.c so they aren't declared static. */ -/* ----- 3d arrays ------- */ -RealD * _rootsXphen, /* relative roots X phen in each lyr,grp,pd */ - * _roots_active, /* "active" in terms of size and phenology */ - * _roots_active_rel; - - -/* ----- 2D arrays ------- */ -/* malloc'ed here for consistency but only used */ -/* in sxw_resource.c and sxw_soilwat.c */ - - /* rgroup by layer, ie, group-level values */ -RealD * _roots_max, /* read from root distr. file */ - * _roots_active_sum, /* used in sxw_resource */ - - /* rgroup by period */ - * _phen; /* phenology read from file */ - -/* simple vectors hold the resource information for each group */ -/* curr/equ gives the available/required ratio */ -RealF *_resource_cur; /*[MAX_RGROUPS];*/ /* current resource availability for each STEPPE functional type */ - // Window of transpiration used by _transp_contribution_by_group() in sxw_resource.c // "Window" refers to the number of years over which transpiration data is averaged. -transp_t transp_window; - -// Amount of additional transpiration added for the current year -RealF added_transp; - +transp_t* transp_window; pcg32_random_t resource_rng; //rng for swx_resource.c functions. +SXW_resourceType* SXWResources; /* and one vector for the production constants */ RealD _prod_litter[MAX_MONTHS]; @@ -138,6 +115,7 @@ static TimeInt _debugyrs[100], _debugyrs_cnt; /*************** Local Function Declarations ***************/ /***********************************************************/ +static void _allocate_memory(void); static void _read_files( void ); static void _read_roots_max(void); static void _read_phen(void); @@ -154,12 +132,14 @@ void _print_debuginfo(void); void debugCleanUp(void); static void _make_swc_array(void); static void SXW_SW_Setup_Echo(void); -static void SXW_Reinit(void); +static void SXW_Reinit(char* SOILWAT_file); -//these last four functions are to be used in ST_grid.c -void load_sxw_memory( RealD * grid_roots_max, RealD* grid_rootsXphen, RealD* grid_roots_active, RealD* grid_roots_active_rel, RealD* grid_roots_active_sum, RealD* grid_phen, RealD* grid_prod_bmass, RealD* grid_prod_pctlive ); void save_sxw_memory( RealD * grid_roots_max, RealD* grid_rootsXphen, RealD* grid_roots_active, RealD* grid_roots_active_rel, RealD* grid_roots_active_sum, RealD* grid_phen, RealD* grid_prod_bmass, RealD* grid_prod_pctlive ); -void free_sxw_memory( void ); +SXW_t* getSXW(void); +SXW_resourceType* getSXWResources(void); +transp_t* getTranspWindow(void); + +void copy_sxw_variables(SXW_t* newSXW, SXW_resourceType* newSXWResources, transp_t* newTransp_window); /****************** Begin Function Code ********************/ /***********************************************************/ @@ -176,18 +156,19 @@ void SXW_Init( Bool init_SW, char *f_roots ) { * match sxwroots.in */ char roots[MAX_FILENAMESIZE] = { '\0' }; - - _resource_cur = (RealF *)Mem_Calloc(Globals.max_rgroups, sizeof(RealF), "SXW_Init"); -RandSeed(Globals.randseed, &resource_rng); + RandSeed(SuperGlobals.randseed, &resource_rng); + + _allocate_memory(); //Allocate memory for all local pointers - _sxwfiles[0] = &SXW.f_roots; - _sxwfiles[1] = &SXW.f_phen; - _sxwfiles[2] = &SXW.f_bvt; - _sxwfiles[3] = &SXW.f_prod; - _sxwfiles[4] = &SXW.f_watin; + _sxwfiles[0] = &SXW->f_roots; + _sxwfiles[1] = &SXW->f_phen; + _sxwfiles[3] = &SXW->f_prod; + _sxwfiles[2] = &SXW->f_bvt; + _sxwfiles[4] = &SXW->f_watin; - SXW.NGrps = Globals.grpCount; + SXW->debugfile = NULL; + SXW->NGrps = Globals->grpCount; _read_files(); if(f_roots != NULL) { @@ -195,34 +176,37 @@ RandSeed(Globals.randseed, &resource_rng); strcpy(roots, DirName(*_sxwfiles[0])); strcat(roots, f_roots); Mem_Free(*_sxwfiles[0]); - _sxwfiles[0] = &SXW.f_roots; + _sxwfiles[0] = &SXW->f_roots; *_sxwfiles[0] = Str_Dup(roots); } - SXW.NPds = MAX_MONTHS; + SXW->NPds = MAX_MONTHS; _read_watin(); - if (SXW.debugfile) + if (SXW->debugfile) _read_debugfile(); if (init_SW) { - SXW_Reinit(); + SXW_Reinit(SXW->f_watin); } - SXW.NTrLyrs = SW_Site.n_transp_lyrs[0]; - if(SW_Site.n_transp_lyrs[1] > SXW.NTrLyrs) - SXW.NTrLyrs = SW_Site.n_transp_lyrs[1]; - if(SW_Site.n_transp_lyrs[3] > SXW.NTrLyrs) - SXW.NTrLyrs = SW_Site.n_transp_lyrs[3]; - if(SW_Site.n_transp_lyrs[2] > SXW.NTrLyrs) - SXW.NTrLyrs = SW_Site.n_transp_lyrs[2]; - - SXW.NSoLyrs = SW_Site.n_layers; - - printf("Number of layers: %d\n", SW_Site.n_layers); - printf("Number of iterations: %d\n", Globals.runModelIterations); - printf("Number of years: %d\n", Globals.runModelYears); + SXW->NTrLyrs = SW_Site.n_transp_lyrs[0]; + if(SW_Site.n_transp_lyrs[1] > SXW->NTrLyrs) + SXW->NTrLyrs = SW_Site.n_transp_lyrs[1]; + if(SW_Site.n_transp_lyrs[3] > SXW->NTrLyrs) + SXW->NTrLyrs = SW_Site.n_transp_lyrs[3]; + if(SW_Site.n_transp_lyrs[2] > SXW->NTrLyrs) + SXW->NTrLyrs = SW_Site.n_transp_lyrs[2]; + + SXW->NSoLyrs = SW_Site.n_layers; + + /* Print general information to stdout. + If we are using gridded mode this functionallity will be handled in ST_grid.c */ + if(!UseGrid){ + printf("Number of iterations: %d\n", SuperGlobals.runModelIterations); + printf("Number of years: %d\n", SuperGlobals.runModelYears); + } _make_arrays(); @@ -243,14 +227,14 @@ RandSeed(Globals.randseed, &resource_rng); @brief This function initializes and allocates SOILWAT2 structures, and reads SOIILWAT2 inputs. */ -static void SXW_Reinit(void) { +static void SXW_Reinit(char* SOILWAT_file) { char *temp; - temp = strdup(SXW.f_watin); + temp = strdup(SOILWAT_file); SW_CTL_init_model(temp); SW_CTL_obtain_inputs(); SW_OUT_set_SXWrequests(); - free(temp); + free(temp); } @@ -265,9 +249,9 @@ static void SXW_Reinit(void) { over from one STEPWAT2 iteration to the next. They are only de-allocated at the end of an entire STEPWAT2 run (see `ST_main.c/main()`). */ -void SXW_Reset(void) { +void SXW_Reset(char* SOILWAT_file) { SW_CTL_clear_model(FALSE); // don't reset output arrays - SXW_Reinit(); + SXW_Reinit(SOILWAT_file); } void SXW_InitPlot (void) { @@ -296,7 +280,7 @@ void SXW_Run_SOILWAT(void) { SppIndex sp; RealF *sizes; - sizes = (RealF *) Mem_Calloc(Globals.max_rgroups, sizeof (RealF), "SXW_Run_SOILWAT"); + sizes = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF), "SXW_Run_SOILWAT"); /* Compute current STEPPE biomass which represents last year's biomass and biomass due to establishment this year (for perennials) and biomass due to establishment this year (for annuals) */ ForEachGroup(g) { @@ -319,7 +303,7 @@ void SXW_Run_SOILWAT(void) { _sxw_sw_setup(sizes); // Initialize `SXW` values for current year's run: - SXW.aet = 0.; /* used to be in sw_setup() but it needs clearing each run */ + SXW->aet = 0.; /* used to be in sw_setup() but it needs clearing each run */ //SXW_SW_Setup_Echo(); _sxw_sw_run(); @@ -382,10 +366,10 @@ void SXW_SW_Setup_Echo(void) { } // adding values to sxw structure for use in ST_stats.c - /*SXW.grass_cover = SW_VegProd.grass.conv_stcr; - SXW.shrub_cover = SW_VegProd.shrub.conv_stcr; - SXW.tree_cover = SW_VegProd.tree.conv_stcr; - SXW.forbs_cover = SW_VegProd.forb.conv_stcr;*/ + /*SXW->grass_cover = SW_VegProd.grass.conv_stcr; + SXW->shrub_cover = SW_VegProd.shrub.conv_stcr; + SXW->tree_cover = SW_VegProd.tree.conv_stcr; + SXW->forbs_cover = SW_VegProd.forb.conv_stcr;*/ fprintf(f, "\n"); @@ -397,7 +381,7 @@ RealF SXW_GetTranspiration( GrpIndex rg) { /* see _sxw_update_resource() for _resource_cur[] */ //printf("SXW_GetTranspiration _resource_cur[%d] = %.5f \n", rg, _resource_cur[rg]); - return _resource_cur[rg]; + return SXWResources->_resource_cur[rg]; } void SXW_PrintDebug(Bool cleanup) { @@ -420,21 +404,65 @@ void SXW_PrintDebug(Bool cleanup) { insertInfo(); insertSXWPhen(); insertSXWProd(); - insertRootsXphen(_rootsXphen); + insertRootsXphen(SXWResources->_rootsXphen); } insertInputVars(); insertInputProd(); insertInputSoils(); - insertOutputVars(_resource_cur, added_transp); - insertRgroupInfo(_resource_cur); + insertOutputVars(SXWResources->_resource_cur, transp_window->added_transp); + insertRgroupInfo(SXWResources->_resource_cur); insertOutputProd(&SW_VegProd); - insertRootsSum(_roots_active_sum); - insertRootsRelative(_roots_active_rel); + insertRootsSum(SXWResources->_roots_active_sum); + insertRootsRelative(SXWResources->_roots_active_rel); insertTranspiration(); insertSWCBulk(); } } +/* Allocate memory for sxw local variables. This should only be called once per simulation. */ +static void _allocate_memory(void){ + transp_window = (transp_t*) Mem_Calloc(1, sizeof(transp_t), "_allocate_memory: transp_window"); + + /* Set the size of our transpiration window. */ + if(Globals->transp_window > MAX_WINDOW){ + LogError(logfp, LOGWARN, "Requested transp_window (%d) > %d. Setting transp_window to %d.", + Globals->transp_window, MAX_WINDOW, MAX_WINDOW); + transp_window->size = MAX_WINDOW; + } else { + transp_window->size = Globals->transp_window; + } + + transp_window->ratios = (RealF*) Mem_Calloc(transp_window->size, sizeof(RealF), "_allocate_memory: transp_window->ratios"); + transp_window->transp = (RealF*) Mem_Calloc(transp_window->size, sizeof(RealF), "_allocate_memory: transp_window->transp"); + transp_window->SoS_array = (RealF*) Mem_Calloc(transp_window->size, sizeof(RealF), "_allocate_memory: transp_window->SoS_array"); + + SXW = (SXW_t*) Mem_Calloc(1, sizeof(SXW_t), "_allocate_memory: SXW"); + SXWResources = (SXW_resourceType*) Mem_Calloc(1, sizeof(SXW_resourceType), "_allocate_memory: SXWResources"); + + SXWResources->_resource_cur = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF), "_allocate_memory: _resource_cur"); +} + +/* Returns a pointer to the local SXW variable. */ +SXW_t* getSXW(void){ + return SXW; +} + +/* Returns a pointer to the local SXWResources variable. */ +SXW_resourceType* getSXWResources(void){ + return SXWResources; +} + +/* Returns a pointer to the local transp_window variable. */ +transp_t* getTranspWindow(void){ + return transp_window; +} + +/* Shallow copy variables into the local sxw variables. */ +void copy_sxw_variables(SXW_t* newSXW, SXW_resourceType* newSXWResources, transp_t* newTransp_window){ + SXW = newSXW; + SXWResources = newSXWResources; + transp_window = newTransp_window; +} static void _read_files( void ) { /*======================================================*/ @@ -442,8 +470,8 @@ static void _read_files( void ) { FILE *fin; int i, nfiles = SXW_NFILES; - SXW.f_files = Parm_name(F_SXW); /* aliased */ - MyFileName = SXW.f_files; + SXW->f_files = Parm_name(F_SXW); /* aliased */ + MyFileName = SXW->f_files; fin = OpenFile(MyFileName,"r"); for(i=0; i < nfiles; i++) { @@ -469,9 +497,9 @@ static void _read_roots_max(void) { char *name; FILE *fp; - name = (char *)Mem_Calloc(Globals.max_groupnamelen + 1, sizeof(char), "_read_roots_max"); + name = (char *)Mem_Calloc(SuperGlobals.max_groupnamelen + 1, sizeof(char), "_read_roots_max"); - MyFileName = SXW.f_roots; + MyFileName = SXW->f_roots; fp = OpenFile(MyFileName, "r"); while (GetALine(fp, inbuf)) { @@ -485,17 +513,17 @@ static void _read_roots_max(void) { cnt++; lyr = 0; while ((p = strtok(NULL, " \t"))) { - _roots_max[Ilg(lyr, g)] = atof(p); + SXWResources->_roots_max[Ilg(lyr, g)] = atof(p); lyr++; } - if (lyr != SXW.NTrLyrs) { + if (lyr != SXW->NTrLyrs) { LogError(logfp, LOGFATAL, "%s: Group : %s : Missing layer values. Match up with soils.in file. Include zeros if necessary. Layers needed %u. Layers defined %u", - MyFileName, name, SXW.NTrLyrs, lyr); + MyFileName, name, SXW->NTrLyrs, lyr); } } - if (cnt < Globals.grpCount) { + if (cnt < Globals->grpCount) { LogError(logfp, LOGFATAL, "%s: Not enough valid groups found.", MyFileName); } @@ -514,7 +542,7 @@ static void _read_phen(void) { char *p; FILE *fp; - MyFileName = SXW.f_phen; + MyFileName = SXW->f_phen; fp = OpenFile(MyFileName,"r"); @@ -532,13 +560,13 @@ static void _read_phen(void) { LogError(logfp, LOGFATAL, "%s: More than 12 months of data found.", MyFileName); } - _phen[Igp(g,m)] = atof(p); + SXWResources->_phen[Igp(g,m)] = atof(p); m++; } } - if (cnt < Globals.grpCount) { + if (cnt < Globals->grpCount) { LogError(logfp, LOGFATAL, "%s: Not enough valid groups found.", MyFileName); } @@ -558,7 +586,7 @@ static void _read_bvt(void) { FILE *fp; RealF bmass, transp; - MyFileName = SXW.f_bvt; + MyFileName = SXW->f_bvt; fp = OpenFile(MyFileName,"r"); GetALine(fp, inbuf); @@ -570,7 +598,7 @@ static void _read_bvt(void) { CloseFile(&fp); - _bvt = bmass / transp; + SXWResources->_bvt = bmass / transp; } @@ -584,11 +612,11 @@ static void _read_prod(void) { IntUS cnt = 0; char *p; char * pch; - MyFileName = SXW.f_prod; + MyFileName = SXW->f_prod; fp = OpenFile(MyFileName, "r"); while (GetALine(fp, inbuf)) { - x = sscanf(inbuf, "%lf", &_prod_litter[mon]); + x = sscanf(inbuf, "%lf", &SXWResources->_prod_litter[mon]); if (x < 1) { LogError(logfp, LOGFATAL, "%s: invalid record for litter %d.", MyFileName, mon + 1); @@ -623,15 +651,15 @@ static void _read_prod(void) { LogError(logfp, LOGFATAL, "%s: More than 12 months of data found.", MyFileName); } - _prod_bmass[Igp(g, mon)] = atof(p); + SXWResources->_prod_bmass[Igp(g, mon)] = atof(p); mon++; } cnt++; - if(cnt == SXW.NGrps) + if(cnt == SXW->NGrps) break; } - if (cnt < Globals.grpCount) { + if (cnt < Globals->grpCount) { LogError(logfp, LOGFATAL, "%s: Not enough valid groups found.", MyFileName); } @@ -658,15 +686,15 @@ static void _read_prod(void) { LogError(logfp, LOGFATAL, "%s: More than 12 months of data found.", MyFileName); } - _prod_pctlive[Igp(g, mon)] = atof(p); + SXWResources->_prod_pctlive[Igp(g, mon)] = atof(p); mon++; } cnt++; - if (cnt == SXW.NGrps) + if (cnt == SXW->NGrps) break; } - if (cnt < Globals.grpCount) { + if (cnt < Globals->grpCount) { LogError(logfp, LOGFATAL, "%s: Not enough valid groups found.", MyFileName); } @@ -691,13 +719,13 @@ static void _read_watin(void) { int lineno = 0; Bool found = FALSE; - MyFileName = SXW.f_watin; + MyFileName = SXW->f_watin; f = OpenFile(MyFileName, "r"); while( GetALine(f, inbuf) ) { if (++lineno == (eOutput + 2)) { - strcpy(_swOutDefName, DirName(SXW.f_watin)); + strcpy(_swOutDefName, DirName(SXW->f_watin)); strcat(_swOutDefName, inbuf); found = TRUE; break; @@ -729,17 +757,17 @@ static void _make_roots_arrays(void) { int size; char *fstr = "_make_roots_array()"; - size = SXW.NGrps * SXW.NTrLyrs; - _roots_max = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + size = SXW->NGrps * SXW->NTrLyrs; + SXWResources->_roots_max = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); - size = SXW.NGrps * SXW.NPds * SXW.NTrLyrs; - _rootsXphen = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); - _roots_active = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); - _roots_active_rel = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + size = SXW->NGrps * SXW->NPds * SXW->NTrLyrs; + SXWResources->_rootsXphen = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + SXWResources->_roots_active = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + SXWResources->_roots_active_rel = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); //4 - Grass,Frob,Tree,Shrub - size = NVEGTYPES * SXW.NPds * SXW.NTrLyrs; - _roots_active_sum = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + size = NVEGTYPES * SXW->NPds * SXW->NTrLyrs; + SXWResources->_roots_active_sum = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); } static void _make_phen_arrays(void) { @@ -747,8 +775,8 @@ static void _make_phen_arrays(void) { int size; char *fstr = "_make_phen_arrays()"; - size = SXW.NGrps * MAX_MONTHS; - _phen = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + size = SXW->NGrps * MAX_MONTHS; + SXWResources->_phen = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); } @@ -756,37 +784,37 @@ static void _make_prod_arrays(void) { int size; char *fstr = "_make_phen_arrays()"; - size = SXW.NGrps * MAX_MONTHS; - _prod_bmass = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); - _prod_pctlive = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + size = SXW->NGrps * MAX_MONTHS; + SXWResources->_prod_bmass = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + SXWResources->_prod_pctlive = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); } static void _make_transp_arrays(void) { /*======================================================*/ -/* SXW.transp holds year-to-year values and is populated in SOILWAT. +/* SXW->transp holds year-to-year values and is populated in SOILWAT. * both are indexed by the macro Ilp(). */ char *fstr = "_make_transp_array()"; int size, k; - size = SXW.NPds * SXW.NSoLyrs; // monthly values for each soil layer - SXW.transpTotal = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + size = SXW->NPds * SXW->NSoLyrs; // monthly values for each soil layer + SXW->transpTotal = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); ForEachVegType(k) { - SXW.transpVeg[k] = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); + SXW->transpVeg[k] = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr); } } static void _make_swc_array(void) { /*======================================================*/ -/* SXW.swc holds year-to-year values and is populated in SOILWAT. +/* SXW->swc holds year-to-year values and is populated in SOILWAT. * it is indexed by the macro Ilp(). only used if soilwat option * specified with debugfile */ char *fstr = "_make_swc_array()"; - int size = SXW.NPds * SXW.NSoLyrs; // monthly values for each soil layer + int size = SXW->NPds * SXW->NSoLyrs; // monthly values for each soil layer - SXW.swc = (RealF *) Mem_Calloc(size, sizeof(RealF *), fstr); + SXW->swc = (RealF *) Mem_Calloc(size, sizeof(RealF *), fstr); } static void _read_debugfile(void) { @@ -820,7 +848,7 @@ static void _read_debugfile(void) { TimeInt i; char name[256] = {0}; - f = OpenFile(SXW.debugfile, "r"); + f = OpenFile(SXW->debugfile, "r"); /* get name of output file */ if (!GetALine(f, inbuf)) { @@ -908,7 +936,7 @@ void _print_debuginfo(void) { //ForEachTranspLayer(t) { fprintf(f, "%d", t + 1); ForEachTrPeriod(p) - fprintf(f, "\t%.4f", _rootsXphen[Iglp(r, t, p)]); + fprintf(f, "\t%.4f", SXWResources->_rootsXphen[Iglp(r, t, p)]); fprintf(f, "\n"); } } @@ -918,24 +946,23 @@ void _print_debuginfo(void) { /* sum actual total transpiration */ ForEachTrPeriod(p) { - //ForEachTranspLayer(t) sum += SXW.transp[Ilp(t,p)]; - for (t = 0; t < SXW.NSoLyrs; t++) - sum += SXW.transpTotal[Ilp(t, p)]; + for (t = 0; t < SXW->NSoLyrs; t++) + sum += SXW->transpTotal[Ilp(t, p)]; } fprintf(f, "\n================== %d =============================\n", SW_Model.year); - fprintf(f, "MAP = %d(mm)\tMAT = %5.2f(C)\tAET = %5.4f(cm)\tT = %5.4f(cm)\tTADDED = %5.4f(cm)\tAT = %5.4f(cm)\n\n", Env.ppt, Env.temp, SXW.aet, sum, added_transp, sum + added_transp); + fprintf(f, "MAP = %d(mm)\tMAT = %5.2f(C)\tAET = %5.4f(cm)\tT = %5.4f(cm)\tTADDED = %5.4f(cm)\tAT = %5.4f(cm)\n\n", Env->ppt, Env->temp, SXW->aet, sum, transp_window->added_transp, sum + transp_window->added_transp); fprintf(f, "Group \tRelsize\tPR\tResource_cur\tResource_cur\n"); fprintf(f, "----- \t-------\t-----\t-no scaling-\t-with scaling-\n"); ForEachGroup(r) { sum1 += getRGroupRelsize(r); sum2 += RGroup[r]->pr; - sum3 += _resource_cur[r]; - fprintf(f, "%s\t%.4f\t%.4f\t%.4f\t\t%.4f\n", RGroup[r]->name, getRGroupRelsize(r), RGroup[r]->pr, _resource_cur[r]/_bvt, _resource_cur[r]); + sum3 += SXWResources->_resource_cur[r]; + fprintf(f, "%s\t%.4f\t%.4f\t%.4f\t\t%.4f\n", RGroup[r]->name, getRGroupRelsize(r), RGroup[r]->pr, SXWResources->_resource_cur[r]/_bvt, SXWResources->_resource_cur[r]); } fprintf(f, "----- \t-------\t-----\t-----\t\t-----\n"); - fprintf(f, "%s\t\t%.4f\t%.4f\t%.4f\t\t%.4f\n", "Total", sum1, sum2, sum3/_bvt, sum3); + fprintf(f, "%s\t\t%.4f\t%.4f\t%.4f\t\t%.4f\n", "Total", sum1, sum2, sum3/SXWResources->_bvt, sum3); fprintf(f, "\n------ Production Values Daily Summed Across Types Monthly Averaged -------\n"); fprintf(f, "Month\tBMass\tPctLive\tLAIlive\tLAItotal\tTotAGB\n"); @@ -997,10 +1024,10 @@ void _print_debuginfo(void) { ForEachTrPeriod(p) fprintf(f, "\t%d", p + 1); fprintf(f, "\n"); - for (l = 0; l < SXW.NTrLyrs; l++) { + for (l = 0; l < SXW->NTrLyrs; l++) { fprintf(f, "%d", t + 1); ForEachTrPeriod(p) - fprintf(f, "\t%.4f", _roots_active_sum[Itlp(t, l, p)]); + fprintf(f, "\t%.4f", SXWResources->_roots_active_sum[Itlp(t, l, p)]); fprintf(f, "\n"); } } @@ -1016,26 +1043,23 @@ void _print_debuginfo(void) { fprintf(f, "\n"); int nLyrs = getNTranspLayers(RGroup[r]->veg_prod_type); for (t = 0; t < nLyrs; t++) { - //ForEachTranspLayer(t) { fprintf(f, "%d", t + 1); ForEachTrPeriod(p) - fprintf(f, "\t%.4f", _roots_active_rel[Iglp(r, t, p)]); + fprintf(f, "\t%.4f", SXWResources->_roots_active_rel[Iglp(r, t, p)]); fprintf(f, "\n"); } } fprintf(f, "\n------ Transpiration Total Values -------\nPeriod:"); - //ForEachTranspLayer(t) - for (t = 0; t < SXW.NSoLyrs; t++) + for (t = 0; t < SXW->NSoLyrs; t++) fprintf(f, "\t\tL%d", t + 1); fprintf(f, "\n"); ForEachTrPeriod(p) { fprintf(f, "%d : ", p + 1); - //ForEachTranspLayer(t) - for (t = 0; t < SXW.NSoLyrs; t++) - fprintf(f, "\t%.4f", SXW.transpTotal[Ilp(t, p)]); + for (t = 0; t < SXW->NSoLyrs; t++) + fprintf(f, "\t%.4f", SXW->transpTotal[Ilp(t, p)]); fprintf(f, "\n"); } @@ -1044,7 +1068,7 @@ void _print_debuginfo(void) { { fprintf(f, "%d : ", p + 1); ForEachSoilLayer(t) - fprintf(f, "\t%5.4f", SXW.swc[Ilp(t, p)]); + fprintf(f, "\t%5.4f", SXW->swc[Ilp(t, p)]); fprintf(f, "\n"); } @@ -1081,7 +1105,7 @@ void SXW_SetMemoryRefs( void) { NoteMemoryRef(_phen); NoteMemoryRef(_phen_grp_rel); NoteMemoryRef(_transp_grp_totals); - NoteMemoryRef(SXW.transp); + NoteMemoryRef(SXW->transp); SW_CTL_SetMemoryRefs(); @@ -1124,68 +1148,46 @@ int getNTranspLayers(int veg_prod_type) { void free_all_sxw_memory( void ) { int k; - free_sxw_memory(); - Mem_Free(SXW.f_files); - Mem_Free(SXW.f_roots); - Mem_Free(SXW.f_phen); - Mem_Free(SXW.f_bvt); - Mem_Free(SXW.f_prod); - Mem_Free(SXW.f_watin); - - Mem_Free(SXW.transpTotal); + /* Free transp_window */ + Mem_Free(transp_window->ratios); + Mem_Free(transp_window->transp); + Mem_Free(transp_window->SoS_array); + Mem_Free(transp_window); + + /* Free SXW */ + Mem_Free(SXW->f_roots); + Mem_Free(SXW->f_phen); + Mem_Free(SXW->f_bvt); + Mem_Free(SXW->f_prod); + Mem_Free(SXW->f_watin); + Mem_Free(SXW->transpTotal); ForEachVegType(k) { - Mem_Free(SXW.transpVeg[k]); + Mem_Free(SXW->transpVeg[k]); } - - //Mem_Free(SXW.sum_dSWA_repartitioned); // required for `_SWA_contribution_by_group` - - Mem_Free(SXW.swc); -} - -/***********************************************************/ -void free_sxw_memory( void ) { - Mem_Free(_roots_max); - Mem_Free(_rootsXphen); - Mem_Free(_roots_active); - Mem_Free(_roots_active_rel); - Mem_Free(_roots_active_sum); - Mem_Free(_phen); - Mem_Free(_prod_bmass); - Mem_Free(_prod_pctlive); -} - -/***********************************************************/ -void load_sxw_memory( RealD* grid_roots_max, RealD* grid_rootsXphen, RealD* grid_roots_active, RealD* grid_roots_active_rel, RealD* grid_roots_active_sum, RealD* grid_phen, RealD* grid_prod_bmass, RealD* grid_prod_pctlive ) { - //load memory from the grid - free_sxw_memory(); - _roots_max = Mem_Calloc(SXW.NGrps * SXW.NTrLyrs, sizeof(RealD), "load_sxw_memory()"); - _rootsXphen = Mem_Calloc(SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), "load_sxw_memory()"); - _roots_active = Mem_Calloc(SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), "load_sxw_memory()"); - _roots_active_rel = Mem_Calloc(SXW.NGrps * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), "load_sxw_memory()"); - _roots_active_sum = Mem_Calloc(NVEGTYPES * SXW.NPds * SXW.NTrLyrs, sizeof(RealD), "load_sxw_memory()"); - _phen = Mem_Calloc(SXW.NGrps * MAX_MONTHS, sizeof(RealD), "load_sxw_memory()"); - _prod_bmass = Mem_Calloc(SXW.NGrps * MAX_MONTHS, sizeof(RealD), "load_sxw_memory()"); - _prod_pctlive = Mem_Calloc(SXW.NGrps * MAX_MONTHS, sizeof(RealD), "load_sxw_memory()"); - - memcpy(_roots_max, grid_roots_max, SXW.NGrps * SXW.NTrLyrs * sizeof(RealD)); - memcpy(_rootsXphen, grid_rootsXphen, SXW.NGrps * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(_roots_active, grid_roots_active, SXW.NGrps * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(_roots_active_rel, grid_roots_active_rel, SXW.NGrps * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(_roots_active_sum, grid_roots_active_sum, NVEGTYPES * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(_phen, grid_phen, SXW.NGrps * MAX_MONTHS * sizeof(RealD)); - memcpy(_prod_bmass, grid_prod_bmass, SXW.NGrps * MAX_MONTHS * sizeof(RealD)); - memcpy(_prod_pctlive, grid_prod_pctlive, SXW.NGrps * MAX_MONTHS * sizeof(RealD)); + Mem_Free(SXW->swc); + Mem_Free(SXW); + + Mem_Free(SXWResources->_phen); + Mem_Free(SXWResources->_prod_bmass); + Mem_Free(SXWResources->_prod_pctlive); + Mem_Free(SXWResources->_resource_cur); + Mem_Free(SXWResources->_roots_active); + Mem_Free(SXWResources->_roots_active_rel); + Mem_Free(SXWResources->_roots_active_sum); + Mem_Free(SXWResources->_roots_max); + Mem_Free(SXWResources->_rootsXphen); + Mem_Free(SXWResources); } /***********************************************************/ void save_sxw_memory( RealD * grid_roots_max, RealD* grid_rootsXphen, RealD* grid_roots_active, RealD* grid_roots_active_rel, RealD* grid_roots_active_sum, RealD* grid_phen, RealD* grid_prod_bmass, RealD* grid_prod_pctlive ) { //save memory to the grid - memcpy(grid_roots_max, _roots_max, SXW.NGrps * SXW.NTrLyrs * sizeof(RealD)); - memcpy(grid_rootsXphen, _rootsXphen, SXW.NGrps * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(grid_roots_active, _roots_active, SXW.NGrps * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(grid_roots_active_rel, _roots_active_rel, SXW.NGrps * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(grid_roots_active_sum, _roots_active_sum, NVEGTYPES * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); - memcpy(grid_phen, _phen, SXW.NGrps * MAX_MONTHS * sizeof(RealD)); - memcpy(grid_prod_bmass, _prod_bmass, SXW.NGrps * MAX_MONTHS * sizeof(RealD)); - memcpy(grid_prod_pctlive, _prod_pctlive, SXW.NGrps * MAX_MONTHS * sizeof(RealD)); + memcpy(grid_roots_max, SXWResources->_roots_max, SXW->NGrps * SXW->NTrLyrs * sizeof(RealD)); + memcpy(grid_rootsXphen, SXWResources->_rootsXphen, SXW->NGrps * SXW->NPds * SXW->NTrLyrs * sizeof(RealD)); + memcpy(grid_roots_active, SXWResources->_roots_active, SXW->NGrps * SXW->NPds * SXW->NTrLyrs * sizeof(RealD)); + memcpy(grid_roots_active_rel, SXWResources->_roots_active_rel, SXW->NGrps * SXW->NPds * SXW->NTrLyrs * sizeof(RealD)); + memcpy(grid_roots_active_sum, SXWResources->_roots_active_sum, NVEGTYPES * SXW->NPds * SXW->NTrLyrs * sizeof(RealD)); + memcpy(grid_phen, SXWResources->_phen, SXW->NGrps * MAX_MONTHS * sizeof(RealD)); + memcpy(grid_prod_bmass, SXWResources->_prod_bmass, SXW->NGrps * MAX_MONTHS * sizeof(RealD)); + memcpy(grid_prod_pctlive, SXWResources->_prod_pctlive, SXW->NGrps * MAX_MONTHS * sizeof(RealD)); } diff --git a/sxw.h b/sxw.h index f895a75b..42ab0805 100644 --- a/sxw.h +++ b/sxw.h @@ -15,6 +15,10 @@ #ifndef SXW_DEF #define SXW_DEF +#define SXW_NFILES 5 +// The number of transpiration values retained by transp_data +#define MAX_WINDOW 100 + #include "generic.h" #include "SW_Times.h" #include "ST_defines.h" @@ -59,10 +63,7 @@ struct stepwat_st { // ------ DEBUG stuff: char *debugfile; /* added in ST_Main(), read to get debug instructions */ -}; - -// The number of transpiration values retained by transp_data -#define MAX_WINDOW 100 +} typedef SXW_t; // transp_data stores three arrays: ratios, transp, and sum of squares. These arrays form // a moving window that stores "size" years worth of previous transpiration data. @@ -96,48 +97,80 @@ struct transp_data { // ratios[] stores (transpiration/precipitation) values. It is used to keep track of // what value needs to be removed from the moving average. - RealF ratios[MAX_WINDOW]; // transp/ppt + RealF* ratios; // transp/ppt // transp[] stores transpiration values. It is used to keep track of what value needs to be // removed from the moving ratio_average. - RealF transp[MAX_WINDOW]; // transp + RealF* transp; // transp //SoS_array[] stores the sum of squares values (xi - mean)^2 for the previous (size) iterations. - RealF SoS_array[MAX_WINDOW]; //(xi - mean)^2 -}; + RealF* SoS_array; //(xi - mean)^2 -typedef struct transp_data transp_t; + // Amount of additional transpiration added for the current year + RealF added_transp; -#define SXW_NFILES 5 + // _transp_contribution_by_group() has different behavior for production years and setup years. + // this variable keeps track of what year last year was, to make sure that the year actually + // incremented. If it did NOT, then this is a setup year. + int lastYear; + +} typedef transp_t; + +struct temp_SXW_st{ + /* ----- 3d arrays ------- */ + RealD * _rootsXphen, /* relative roots X phen in each lyr,grp,pd */ + * _roots_active, // "active" in terms of size and phenology + // relative to the total roots_phen_lyr_group + * _roots_active_rel; + + + /* ----- 2D arrays ------- */ + /* rgroup by layer, ie, group-level values */ + RealD * _roots_max, // root distribution with depth for STEPPE functional + // groups, read from input. + * _roots_active_sum, // active roots in each month and soil layer for + // STEPPE functional groups in the current year. + /* rgroup by period */ + * _phen; // phenological activity for each month for STEPPE + // functional groups, read from input. -typedef struct stepwat_st SXW_t; + /* simple vectors hold the resource information for each group */ + /* curr/equ gives the available/required ratio */ + RealF *_resource_cur; /* current resource availability for each STEPPE functional type */ -#define ForEachTrPeriod(i) for((i)=0; (i)< SXW.NPds; (i)++) + /* one vector for the production constants */ + RealD _prod_litter[MAX_MONTHS]; + RealD * _prod_bmass; + RealD * _prod_pctlive; + RealF _bvt; /* ratio of biomass/m2 / transp/m2 */ + +} typedef SXW_resourceType; + +#define ForEachTrPeriod(i) for((i)=0; (i)< SXW->NPds; (i)++) /* convert 3-d index to actual array index for group/layer/phenology 3d table */ -#define Iglp(g,l,p) (((g)*SXW.NTrLyrs*SXW.NPds) + ((l)*SXW.NPds) + (p)) +#define Iglp(g,l,p) (((g)*SXW->NTrLyrs*SXW->NPds) + ((l)*SXW->NPds) + (p)) /* convert 3-d index to actual array index for * veg-prod-type/layer/phenology */ -#define Itlp(t,l,p) (((t)*SXW.NTrLyrs*SXW.NPds) + ((l)*SXW.NPds) + (p)) - +#define Itlp(t,l,p) (((t)*SXW->NTrLyrs*SXW->NPds) + ((l)*SXW->NPds) + (p)) // veg type, layer, timeperiod -#define Ivlp(v,l,p) (((v)*NVEGTYPES * SXW.NTrLyrs * SXW.NPds) + ((l)*SXW.NTrLyrs * SXW.NPds) + ((p)*SXW.NPds)) +#define Ivlp(v,l,p) (((v)*NVEGTYPES * SXW->NTrLyrs * SXW.NPds) + ((l)*SXW->NTrLyrs * SXW->NPds) + ((p)*SXW->NPds)) /* convert 2d layer by period indices to layer/phenology 1D index */ -#define Ilp(l,p) ((l)*SXW.NPds + (p)) +#define Ilp(l,p) ((l)*SXW->NPds + (p)) /* convert 2d group by period indices to group/phenology 1D index */ -#define Igp(g,p) ((g)*SXW.NPds + (p)) +#define Igp(g,p) ((g)*SXW->NPds + (p)) /* convert 2d group by layer indices to layer/period 1D index */ -#define Ilg(l,g) ((l)*SXW.NGrps + (g)) +#define Ilg(l,g) ((l)*SXW->NGrps + (g)) #endif diff --git a/sxw_environs.c b/sxw_environs.c index afa3713f..b50483c5 100644 --- a/sxw_environs.c +++ b/sxw_environs.c @@ -30,14 +30,14 @@ /*************** Global Variable Declarations ***************/ /***********************************************************/ -extern SXW_t SXW; +extern SXW_t* SXW; extern SW_SITE SW_Site; extern SW_MODEL SW_Model; extern SW_SOILWAT SW_Soilwat; extern SW_WEATHER SW_Weather; -extern EnvType Env; +extern EnvType *Env; /*************** Local Variable Declarations ***************/ /***********************************************************/ @@ -55,8 +55,8 @@ void _sxw_set_environs(void) { * need to convert ppt from cm to mm */ //Integer conversion always does floor so .5 is added - Env.ppt = (IntS) (SXW.ppt * 10 + .5); - Env.temp = SXW.temp; + Env->ppt = (IntS) (SXW->ppt * 10 + .5); + Env->temp = SXW->temp; } diff --git a/sxw_funcs.h b/sxw_funcs.h index b19c01dd..d7d6d08d 100644 --- a/sxw_funcs.h +++ b/sxw_funcs.h @@ -20,7 +20,7 @@ RealF SXW_GetTranspiration( GrpIndex rg); int get_SW2_veg_index(int veg_prod_type); void SXW_Init( Bool init_SW, char *f_roots ); -void SXW_Reset(void); +void SXW_Reset(char* SOILWAT_file); void SXW_Run_SOILWAT (void); void SXW_InitPlot (void); void SXW_PrintDebug(Bool cleanup) ; diff --git a/sxw_resource.c b/sxw_resource.c index 94a35b8f..e9d1cc14 100644 --- a/sxw_resource.c +++ b/sxw_resource.c @@ -47,46 +47,15 @@ //extern SW_SOILWAT SW_Soilwat; //extern SW_VEGPROD SW_VegProd; - -/*************** Local Variable Declarations ***************/ -/***********************************************************/ -/* malloc'ed and maybe read in sxw.c but used here */ -/* ----- 3d arrays ------- */ -extern - RealD * _rootsXphen, /* relative roots X phen by layer & group */ - * _roots_active, /*relative to the total roots_phen_lyr_group */ - * _roots_active_rel; - - -/* ----- 2D arrays ------- */ - -extern - /* rgroup by layer */ - RealD * _roots_max, /* root distribution with depth for STEPPE functional groups, read from input */ - * _roots_active_sum, /* active roots in each month and soil layer for STEPPE functional groups in the current year */ - - /* rgroup by period */ - * _phen; /* phenological activity for each month for STEPPE functional groups, read from input */ - -extern - RealF *_resource_cur; /* resources currently available by group*/ - RealF added_transp; /* transpiration added for the current year */ - -extern - RealF _bvt; +extern SXW_resourceType* SXWResources; /* ------ Running Averages ------ */ extern - transp_t transp_window; + transp_t* transp_window; extern pcg32_random_t resource_rng; -// _transp_contribution_by_group() has different behavior for production years and setup years. -// this variable keeps track of what year last year was, to make sure that the year actually -// incremented. If it did NOT, then this is a setup year. -int lastYear; - //void _print_debuginfo(void); /*************** Local Function Declarations ***************/ @@ -108,15 +77,15 @@ void _sxw_root_phen(void) { GrpIndex g; TimeInt p; - for (y = 0; y < (Globals.grpCount * SXW.NPds * SXW.NTrLyrs); y++) - _rootsXphen[y] = 0; + for (y = 0; y < (Globals->grpCount * SXW->NPds * SXW->NTrLyrs); y++) + SXWResources->_rootsXphen[y] = 0; ForEachGroup(g) { int nLyrs = getNTranspLayers(RGroup[g]->veg_prod_type); for (y = 0; y < nLyrs; y++) { ForEachTrPeriod(p) { - _rootsXphen[Iglp(g, y, p)] = _roots_max[Ilg(y, g)] * _phen[Igp(g, p)]; + SXWResources->_rootsXphen[Iglp(g, y, p)] = SXWResources->_roots_max[Ilg(y, g)] * SXWResources->_phen[Igp(g, p)]; } } } @@ -135,7 +104,7 @@ void _sxw_update_resource(void) { RealF *sizes; GrpIndex g; - sizes = (RealF *)Mem_Calloc(Globals.max_rgroups, sizeof(RealF), "_sxw_update_resource"); + sizes = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF), "_sxw_update_resource"); ForEachGroup(g) { @@ -146,23 +115,22 @@ void _sxw_update_resource(void) { sizes[g] = RGroup_GetBiomass(g); } - /* Update the active relative roots based on current biomass values */ + /* Update the active relative roots based on current biomass values */ _sxw_update_root_tables(sizes); /* Assign transpiration (resource availability) to each STEPPE functional group */ - _transp_contribution_by_group(_resource_cur); + _transp_contribution_by_group(SXWResources->_resource_cur); /* Scale transpiration resources by a constant, bvt, to convert resources * (cm) to biomass that can be supported by those resources (g/cm) */ ForEachGroup(g) { -//printf("for groupName= %smresource_cur prior to multiplication: %f\n",RGroup[g]->name, _resource_cur[g]); - _resource_cur[g] = _resource_cur[g] * _bvt; -//printf("for groupName= %s, resource_cur post multiplication: %f\n\n",Rgroup[g]->name, _resource_cur[g]); +//printf("%s: _resource_cur pre-multiplication = %f. Post multiplication = %f.\n",RGroup[g]->name, + //_resource_cur[g], SXWResources->_resource_cur[g] * SXWResources->_bvt); + SXWResources->_resource_cur[g] = SXWResources->_resource_cur[g] * SXWResources->_bvt; } -/* _print_debuginfo(); */ - Mem_Free(sizes); + Mem_Free(sizes); } void _sxw_update_root_tables( RealF sizes[] ) { @@ -178,7 +146,7 @@ void _sxw_update_root_tables( RealF sizes[] ) { int t; /* Set some things to zero where 4 refers to Tree, Shrub, Grass, Forb */ - Mem_Set(_roots_active_sum, 0, NVEGTYPES * SXW.NPds * SXW.NTrLyrs * sizeof(RealD)); + Mem_Set(SXWResources->_roots_active_sum, 0, NVEGTYPES * SXW->NPds * SXW->NTrLyrs * sizeof(RealD)); /* Calculate the active roots in each month and soil layer for each STEPPE * functional group based on the functional group biomass this year */ @@ -188,14 +156,14 @@ void _sxw_update_root_tables( RealF sizes[] ) { for (l = 0; l < nLyrs; l++) { ForEachTrPeriod(p) { - x = _rootsXphen[Iglp(g, l, p)] * sizes[g]; - _roots_active[Iglp(g, l, p)] = x; - _roots_active_sum[Itlp(RGroup[g]->veg_prod_type, l, p)] += x; + x = SXWResources->_rootsXphen[Iglp(g, l, p)] * sizes[g]; + SXWResources->_roots_active[Iglp(g, l, p)] = x; + SXWResources->_roots_active_sum[Itlp(RGroup[g]->veg_prod_type, l, p)] += x; } } } - /* Rescale _roots_active_sum to represent the relative "activity" of a + /* Rescale SXWResources->_roots_active_sum to represent the relative "activity" of a * STEPPE group's roots in a given layer in a given month */ /* Details: for each soil layer `l` and each month (trperiod) `p`, the sum of `_roots_active_rel[Iglp(g, l, p)]` across rgroups `g` must be 1; @@ -208,13 +176,11 @@ void _sxw_update_root_tables( RealF sizes[] ) { { sum_all_veg_types = 0; ForEachVegType(t) { - sum_all_veg_types += _roots_active_sum[Itlp(t, l, p)]; + sum_all_veg_types += SXWResources->_roots_active_sum[Itlp(t, l, p)]; } - _roots_active_rel[Iglp(g, l, p)] = - ZRO(sum_all_veg_types) ? - 0. : - _roots_active[Iglp(g, l, p)] / sum_all_veg_types; + SXWResources->_roots_active_rel[Iglp(g, l, p)] = ZRO(sum_all_veg_types) ? 0. + : SXWResources->_roots_active[Iglp(g, l, p)] / sum_all_veg_types; } } } @@ -237,29 +203,25 @@ static void _transp_contribution_by_group(RealF use_by_group[]) { LyrIndex l; RealD *transp, proportion_total_resources, average_proportion; RealF sumUsedByGroup = 0., sumTranspTotal = 0., TranspRemaining = 0.; - RealF transp_ratio, added_transp = 0, transp_ratio_sd; + RealF transp_ratio, transp_ratio_sd; + transp_window->added_transp = 0; // year 0 is a set up year. No need to calculate transpiration. // if there are multiple iterations the last year will run twice; // once for data and once for tear down. The second "last year" is // equivalent to year 0. - if(Globals.currYear == 0 || Globals.currYear == lastYear) { - transp_window.average = 0; - transp_window.ratio_average = 0; - transp_window.sum_of_sqrs = 0; - if(Globals.transp_window > MAX_WINDOW){ - LogError(logfp, LOGNOTE, "sxw_resource: Transp_window specified in inputs is greater than maximum window.\nInput: %d\nMaximum: %d\nSetting window to %d.\n",Globals.transp_window, MAX_WINDOW,MAX_WINDOW); - Globals.transp_window = MAX_WINDOW; - } - transp_window.size = Globals.transp_window; - transp_window.oldest_index = 0; + if(Globals->currYear == 0 || Globals->currYear == transp_window->lastYear) { + transp_window->average = 0; + transp_window->ratio_average = 0; + transp_window->sum_of_sqrs = 0; + transp_window->oldest_index = 0; return; //no point calculating anything since SOILWAT hasn't run } ForEachGroup(g) //Steppe functional group { use_by_group[g] = 0.; - transp = SXW.transpTotal; + transp = SXW->transpTotal; //Loops through each month and calculates amount of transpiration for each STEPPE functional group //according to whether that group has active living roots in each soil layer for each month @@ -270,10 +232,9 @@ static void _transp_contribution_by_group(RealF use_by_group[]) { ForEachTrPeriod(p) { nLyrs = getNTranspLayers(RGroup[g]->veg_prod_type); for (l = 0; l < nLyrs; l++) { - use_by_group[g] += (RealF) (_roots_active_rel[Iglp(g, l, p)] * transp[Ilp(l, p)]); + use_by_group[g] += (RealF) (SXWResources->_roots_active_rel[Iglp(g, l, p)] * transp[Ilp(l, p)]); } } - //printf("for groupName= %s, use_by_group[g] in transp= %f \n",RGroup[g]->name,use_by_group[g] ); sumUsedByGroup += use_by_group[g]; //printf(" sumUsedByGroup in transp=%f \n",sumUsedByGroup); @@ -300,101 +261,98 @@ static void _transp_contribution_by_group(RealF use_by_group[]) { //Very small amounts of transpiration remain and not perfectly partitioned to functional groups. //This check makes sure any remaining transpiration is divided proportionately among groups. ForEachTrPeriod(p) { - for (t = 0; t < SXW.NSoLyrs; t++) - sumTranspTotal += SXW.transpTotal[Ilp(t, p)]; + for (t = 0; t < SXW->NSoLyrs; t++) + sumTranspTotal += SXW->transpTotal[Ilp(t, p)]; } TranspRemaining = sumTranspTotal - sumUsedByGroup; /* ------------- Begin testing to see if additional transpiration is necessary ------------- */ - transp_ratio = sumTranspTotal / SXW.ppt; + transp_ratio = sumTranspTotal / SXW->ppt; // Determines if the current year transpiration/ppt is greater than 1 standard deviations away // from the mean. If TRUE, add additional transpiration. - if(transp_window.size >= Globals.currYear) //we need to do a running average + if(transp_window->size >= Globals->currYear) //we need to do a running average { // add transpiration to the window - transp_window.transp[transp_window.oldest_index] = sumTranspTotal; + transp_window->transp[transp_window->oldest_index] = sumTranspTotal; //update the average - transp_window.average = get_running_mean(Globals.currYear,transp_window.average, sumTranspTotal); + transp_window->average = get_running_mean(Globals->currYear,transp_window->average, sumTranspTotal); //add the ratio value to the window - transp_window.ratios[transp_window.oldest_index] = transp_ratio; + transp_window->ratios[transp_window->oldest_index] = transp_ratio; //save the last mean. we will need it to calculate the sum of squares - RealF last_ratio = transp_window.ratio_average; + RealF last_ratio = transp_window->ratio_average; //calculate the running mean - transp_window.ratio_average = get_running_mean(Globals.currYear,transp_window.ratio_average,transp_ratio); + transp_window->ratio_average = get_running_mean(Globals->currYear,transp_window->ratio_average,transp_ratio); //calculate the running sum of squares - RealF ssqr = get_running_sqr(last_ratio, transp_window.ratio_average, transp_ratio); + RealF ssqr = get_running_sqr(last_ratio, transp_window->ratio_average, transp_ratio); //add the calculated sum of squares to the running total - transp_window.sum_of_sqrs += ssqr; + transp_window->sum_of_sqrs += ssqr; //add the calculated sum of squares to the array - transp_window.SoS_array[transp_window.oldest_index] = ssqr; + transp_window->SoS_array[transp_window->oldest_index] = ssqr; //calculate the standard deviation - transp_ratio_sd = final_running_sd(Globals.currYear, transp_window.sum_of_sqrs); + transp_ratio_sd = final_running_sd(Globals->currYear, transp_window->sum_of_sqrs); } else { //we need to do a moving window //add the new value, subtract the old value from the average; - transp_window.average += (sumTranspTotal - transp_window.transp[transp_window.oldest_index])/transp_window.size; + transp_window->average += (sumTranspTotal - transp_window->transp[transp_window->oldest_index])/transp_window->size; //add the new value, subtract the old value from the ratio average; - transp_window.ratio_average += (transp_ratio - transp_window.ratios[transp_window.oldest_index])/transp_window.size; + transp_window->ratio_average += (transp_ratio - transp_window->ratios[transp_window->oldest_index])/transp_window->size; //put the new transpiration in the window - transp_window.transp[transp_window.oldest_index] = sumTranspTotal; + transp_window->transp[transp_window->oldest_index] = sumTranspTotal; //put the new ratio in the window - transp_window.ratios[transp_window.oldest_index] = transp_ratio; + transp_window->ratios[transp_window->oldest_index] = transp_ratio; // calculate the new sum of squares value - RealF ssqr = (transp_ratio - transp_window.ratio_average) * (transp_ratio - transp_window.ratio_average); + RealF ssqr = (transp_ratio - transp_window->ratio_average) * (transp_ratio - transp_window->ratio_average); // add the new sum of squares, subtract the old. - transp_window.sum_of_sqrs += ssqr - transp_window.SoS_array[transp_window.oldest_index]; + transp_window->sum_of_sqrs += ssqr - transp_window->SoS_array[transp_window->oldest_index]; // update the sum of squares window. - transp_window.SoS_array[transp_window.oldest_index] = ssqr; + transp_window->SoS_array[transp_window->oldest_index] = ssqr; //calculate the standard deviation - transp_ratio_sd = final_running_sd(transp_window.size, transp_window.sum_of_sqrs); + transp_ratio_sd = final_running_sd(transp_window->size, transp_window->sum_of_sqrs); } - //printf("Year %d: ratio = %f, mean = %f, sos = %f sd = %f\n",Globals.currYear, - // transp_ratio,transp_window.ratio_average, transp_window.sum_of_sqrs, transp_ratio_sd); + //printf("Year %d: ratio = %f, mean = %f, sos = %f sd = %f\n",Globals->currYear, + // transp_ratio,transp_window->ratio_average, transp_window->sum_of_sqrs, transp_ratio_sd); // If this year's transpiration is notably low (1 sd below the mean), add additional transpired water - if (transp_ratio < (transp_window.ratio_average - 1 * transp_ratio_sd)) { - //printf("Year %d below 1 sd: ratio = %f, average = %f, sd = %f\n", Globals.currYear,transp_ratio, - //transp_window.ratio_average, transp_ratio_sd); - RealF min = transp_window.ratio_average - transp_ratio_sd; - RealF max = transp_window.ratio_average + transp_ratio_sd; + if (transp_ratio < (transp_window->ratio_average - 1 * transp_ratio_sd)) { + RealF min = transp_window->ratio_average - transp_ratio_sd; + RealF max = transp_window->ratio_average + transp_ratio_sd; // This transpiration will be added - added_transp = (1 - transp_ratio / RandUniFloatRange(min, max, &resource_rng)) * transp_window.average; - if(added_transp < 0){ + transp_window->added_transp = (1 - transp_ratio / RandUniFloatRange(min, max, &resource_rng)) * transp_window->average; + if(transp_window->added_transp < 0){ LogError(logfp, LOGNOTE, "sxw_resource: Added transpiration less than 0.\n"); } - //printf("Year %d:\tTranspiration to add: %f\n",Globals.currYear,add_transp); - //printf("TranspRemaining: %f\tTranspRemaining+add_transp: %f\n",TranspRemaining,add_transp+TranspRemaining); + //printf("Year %d:\tTranspiration to add: %f\n",Globals->currYear,add_transp); /* -------------------- Recalculate the window including added_transp in the current year -------------------- */ - RealF added_transp_ratio = added_transp / SXW.ppt; + RealF added_transp_ratio = transp_window->added_transp / SXW->ppt; //add added_transp to the average. This is technically part of the current year, so no need to subtract anything. - transp_window.average += added_transp/transp_window.size; + transp_window->average += transp_window->added_transp/transp_window->size; //add added_transp ratio to the ratio average. This is technically part of the current year, so no need to subtract anything. - transp_window.ratio_average += (added_transp_ratio)/transp_window.size; + transp_window->ratio_average += (added_transp_ratio)/transp_window->size; //put the new transpiration in the window. Note: oldest_index has not been incremented, so it points to what was just added - transp_window.transp[transp_window.oldest_index] += added_transp; + transp_window->transp[transp_window->oldest_index] += transp_window->added_transp; //put the new ratio in the window. Note: oldest_index has not been incremented, so it points to what was just added - transp_window.ratios[transp_window.oldest_index] += added_transp_ratio; + transp_window->ratios[transp_window->oldest_index] += added_transp_ratio; // calculate the new sum of squares value - RealF totalTranspRatio = (sumTranspTotal + added_transp)/SXW.ppt; - RealF ssqr = (totalTranspRatio - transp_window.ratio_average) * (totalTranspRatio - transp_window.ratio_average); + RealF totalTranspRatio = (sumTranspTotal + transp_window->added_transp)/SXW->ppt; + RealF ssqr = (totalTranspRatio - transp_window->ratio_average) * (totalTranspRatio - transp_window->ratio_average); // Subtract the sum of squares calculated above, which was stored in the array. Replace it with what was just calculated. - transp_window.sum_of_sqrs += ssqr - transp_window.SoS_array[transp_window.oldest_index]; + transp_window->sum_of_sqrs += ssqr - transp_window->SoS_array[transp_window->oldest_index]; // replace the sum of squares with what we just calculated - transp_window.SoS_array[transp_window.oldest_index] = ssqr; + transp_window->SoS_array[transp_window->oldest_index] = ssqr; /* Adds the additional transpiration to the remaining transpiration * so it can be distributed proportionally to the functional groups. */ - TranspRemaining += added_transp; + TranspRemaining += transp_window->added_transp; } //oldest_index++ accounting for the array bounds - transp_window.oldest_index = (transp_window.oldest_index + 1) % transp_window.size; + transp_window->oldest_index = (transp_window->oldest_index + 1) % transp_window->size; /* ------------ End testing to see if additional transpiration is necessary ---------- */ @@ -409,5 +367,5 @@ static void _transp_contribution_by_group(RealF use_by_group[]) { } //remember the last year. When setting up for a new iteration the same year will appear twice, and we want to skip it the second time - lastYear = Globals.currYear; + transp_window->lastYear = Globals->currYear; } diff --git a/sxw_soilwat.c b/sxw_soilwat.c index 1981d979..629b47f3 100644 --- a/sxw_soilwat.c +++ b/sxw_soilwat.c @@ -60,13 +60,7 @@ extern SW_SITE SW_Site; extern SW_MODEL SW_Model; extern SW_VEGPROD SW_VegProd; - -/*********** Local/Module Variable Declarations ************/ -/***********************************************************/ -extern RealD *_roots_max; -extern RealD _prod_litter[MAX_MONTHS]; -extern RealD * _prod_bmass; -extern RealD * _prod_pctlive; +extern SXW_resourceType* SXWResources; /*************** Local Function Declarations ***************/ /***********************************************************/ @@ -97,7 +91,7 @@ void _sxw_sw_setup (RealF sizes[]) { void _sxw_sw_run(void) { /*======================================================*/ - SW_Model.year = SW_Model.startyr + Globals.currYear-1; + SW_Model.year = SW_Model.startyr + Globals->currYear-1; SW_CTL_run_current_year(); } @@ -105,9 +99,9 @@ void _sxw_sw_clear_transp(void) { /*======================================================*/ int k; - Mem_Set(SXW.transpTotal, 0, SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); + Mem_Set(SXW->transpTotal, 0, SXW->NPds * SXW->NSoLyrs * sizeof(RealD)); ForEachVegType(k) { - Mem_Set(SXW.transpVeg[k], 0, SXW.NPds * SXW.NSoLyrs * sizeof(RealD)); + Mem_Set(SXW->transpVeg[k], 0, SXW->NPds * SXW->NSoLyrs * sizeof(RealD)); } } @@ -130,7 +124,7 @@ static void _update_transp_coeff(void) { ForEachGroup(g) { if (RGroup[g]->veg_prod_type == SW_TREES) if (getNTranspLayers(SW_TREES)) - y->transp_coeff[SW_TREES] += (RealF) _roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; + y->transp_coeff[SW_TREES] += (RealF) SXWResources->_roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; } sum[SW_TREES] += y->transp_coeff[SW_TREES]; } @@ -141,11 +135,11 @@ static void _update_transp_coeff(void) { ForEachGroup(g) if (RGroup[g]->veg_prod_type == SW_SHRUB) { if (getNTranspLayers(SW_SHRUB)) - y->transp_coeff[SW_SHRUB] += (RealF) _roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; + y->transp_coeff[SW_SHRUB] += (RealF) SXWResources->_roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; /*printf("* lyr=%d, group=%s(%d), type=%d, tl=%d, rootmax=%f, relsize2=%f, trco=%f\n", l, RGroup[g]->name, g, RGroup[g]->veg_prod_type, getNTranspLayers(RGroup[g]->veg_prod_type), - _roots_max[Ilg(l, g)], RGroup[g]->relsize, y->transp_coeff[SW_SHRUB]); + SXWResources->_roots_max[Ilg(l, g)], getRGroupRelsize(g), y->transp_coeff[SW_SHRUB]); */ } sum[SW_SHRUB] += y->transp_coeff[SW_SHRUB]; @@ -157,7 +151,7 @@ static void _update_transp_coeff(void) { ForEachGroup(g) { if (RGroup[g]->veg_prod_type == SW_GRASS) if (getNTranspLayers(SW_GRASS)) - y->transp_coeff[SW_GRASS] += (RealF) _roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; + y->transp_coeff[SW_GRASS] += (RealF) SXWResources->_roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; } sum[SW_GRASS] += y->transp_coeff[SW_GRASS]; } @@ -168,7 +162,7 @@ static void _update_transp_coeff(void) { ForEachGroup(g) { if (RGroup[g]->veg_prod_type == SW_FORBS) if (getNTranspLayers(SW_FORBS)) - y->transp_coeff[SW_FORBS] += (RealF) _roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; + y->transp_coeff[SW_FORBS] += (RealF) SXWResources->_roots_max[Ilg(l, g)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; } sum[SW_FORBS] += y->transp_coeff[SW_FORBS]; } @@ -207,13 +201,13 @@ static void _update_productivity(RealF sizes[]) { *bmassg, vegTypeBiomass[NVEGTYPES] = {0.}; - bmassg = (RealF *)Mem_Calloc(Globals.max_rgroups, sizeof(RealF), "_update_productivity"); + bmassg = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF), "_update_productivity"); // totbmass: total biomass in g/m2 // vegTypeBiomass: biomass for each of the SOILWAT2 vegetation types in g/m2 ForEachGroup(g) { - bmassg[g] = sizes[g] / Globals.plotsize; // gram per plot -> gram per m2 + bmassg[g] = sizes[g] / Globals->plotsize; // gram per plot -> gram per m2 totbmass += bmassg[g]; // Sum biomass of resource groups per SOILWAT2 vegetation type @@ -262,12 +256,12 @@ static void _update_productivity(RealF sizes[]) { if (GT(totbmass, 0.)) { ForEachGroup(g) { k = RGroup[g]->veg_prod_type; - v->veg[k].pct_live[m] += _prod_pctlive[Igp(g, m)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; - v->veg[k].biomass[m] += _prod_bmass[Igp(g, m)] * bmassg[g] / v->veg[k].cov.fCover; + v->veg[k].pct_live[m] += SXWResources->_prod_pctlive[Igp(g, m)] * RGroup[g]->rgroupFractionOfVegTypeBiomass; + v->veg[k].biomass[m] += SXWResources->_prod_bmass[Igp(g, m)] * bmassg[g] / v->veg[k].cov.fCover; } ForEachVegType(k) { - v->veg[k].litter[m] = v->veg[k].biomass[m] * _prod_litter[m]; + v->veg[k].litter[m] = v->veg[k].biomass[m] * SXWResources->_prod_litter[m]; } } } diff --git a/sxw_sql.c b/sxw_sql.c index 269a96be..4a41df10 100644 --- a/sxw_sql.c +++ b/sxw_sql.c @@ -15,14 +15,10 @@ #include "sxw.h" extern SW_MODEL SW_Model; -extern SXW_t SXW; +extern SXW_t* SXW; extern SW_SITE SW_Site; extern SW_VEGPROD SW_VegProd; -extern RealD *_phen; -extern RealD _prod_litter[MAX_MONTHS]; -extern RealD * _prod_bmass; -extern RealD * _prod_pctlive; -extern RealF _bvt; +extern SXW_resourceType* SXWResources; static sqlite3 *db; static char sql[1024]; @@ -123,7 +119,7 @@ void insertSXWPhen(void) { { for(m=0;m<12;m++) { sql[0] = 0; - sprintf(sql, "INSERT INTO sxwphen (RGroupID, Month, GrowthPCT) VALUES (%d, %d, %f);", g+1, m+1,_phen[Igp(g,m)]); + sprintf(sql, "INSERT INTO sxwphen (RGroupID, Month, GrowthPCT) VALUES (%d, %d, %f);", g+1, m+1,SXWResources->_phen[Igp(g,m)]); rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); sqlcheck(rc, zErrMsg); } @@ -142,7 +138,8 @@ void insertSXWProd(void) { { for(m=0;m<12;m++) { sql[0] = 0; - sprintf(sql, "INSERT INTO sxwprod (RGroupID, Month, BMASS, LITTER, PCTLIVE) VALUES (%d, %d, %f, %f, %f);", g+1, m+1, _prod_bmass[Igp(g,m)], _prod_litter[m], _prod_pctlive[Igp(g,m)]); + sprintf(sql, "INSERT INTO sxwprod (RGroupID, Month, BMASS, LITTER, PCTLIVE) VALUES (%d, %d, %f, %f, %f);", + g+1, m+1, SXWResources->_prod_bmass[Igp(g,m)], SXWResources->_prod_litter[m], SXWResources->_prod_pctlive[Igp(g,m)]); rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); sqlcheck(rc, zErrMsg); } @@ -156,7 +153,8 @@ void insertInfo() { sql[0] = 0; beginTransaction(); - sprintf(sql, "INSERT INTO info (StartYear, Years, Iterations, RGroups, TranspirationLayers, SoilLayers, PlotSize, BVT) VALUES (%d, %d, %d, %d, %d, %d, %f, %f);", SW_Model.startyr, Globals.runModelYears, Globals.runModelIterations, Globals.grpCount, SXW.NTrLyrs, SXW.NSoLyrs, Globals.plotsize, _bvt); + sprintf(sql, "INSERT INTO info (StartYear, Years, Iterations, RGroups, TranspirationLayers, SoilLayers, PlotSize, BVT) VALUES (%d, %d, %d, %d, %d, %d, %f, %f);", + SW_Model.startyr, SuperGlobals.runModelYears, SuperGlobals.runModelIterations, Globals->grpCount, SXW->NTrLyrs, SXW->NSoLyrs, Globals->plotsize, SXWResources->_bvt); rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); sqlcheck(rc, zErrMsg); endTransaction(); @@ -217,7 +215,7 @@ static void insertSXWinputVarsRow(int year, int iter, double fracGrass, double f void insertInputVars() { int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; SW_VEGPROD *v = &SW_VegProd; beginTransaction(); @@ -250,7 +248,7 @@ static void insertSXWinputProdRow(int year, int iter, int VegProdType, int Month void insertInputProd() { int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; int p; SW_VEGPROD *v = &SW_VegProd; @@ -288,7 +286,7 @@ static void insertSXWinputSoilsRow(int year, int iter, int Layer, double Tree_tr void insertInputSoils() { int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; int l; SW_SITE *s = &SW_Site; @@ -328,7 +326,7 @@ static void insertSXWoutputVarsRow(int year, int iter, int MAP_mm, double MAT_C, void insertOutputVars(RealF * _resource_cur, RealF added_transp) { int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; int p; int t; int r; @@ -339,9 +337,8 @@ void insertOutputVars(RealF * _resource_cur, RealF added_transp) { ForEachTrPeriod(p) { - //ForEachTranspLayer(t) sum += SXW.transp[Ilp(t,p)]; - for (t = 0; t < SXW.NSoLyrs; t++) - sum += SXW.transpTotal[Ilp(t, p)]; + for (t = 0; t < SXW->NSoLyrs; t++) + sum += SXW->transpTotal[Ilp(t, p)]; } ForEachGroup(r) { @@ -350,7 +347,7 @@ void insertOutputVars(RealF * _resource_cur, RealF added_transp) { sum3 += _resource_cur[r]; } beginTransaction(); - insertSXWoutputVarsRow(Year, Iteration, Env.ppt, Env.temp, SXW.aet, sum, added_transp, sum+added_transp, sum1,sum2,sum3); + insertSXWoutputVarsRow(Year, Iteration, Env->ppt, Env->temp, SXW->aet, sum, added_transp, sum+added_transp, sum1,sum2,sum3); endTransaction(); } @@ -379,12 +376,12 @@ static void insertSXWoutputRgroupRow(int year, int iter, int RGroupID, double Bi void insertRgroupInfo(RealF * _resource_cur) { int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; int r; beginTransaction(); ForEachGroup(r) { - insertSXWoutputRgroupRow(Year, Iteration, r+1, RGroup_GetBiomass(r),getRGroupRelsize(r), RGroup[r]->pr, _resource_cur[r]/_bvt, _resource_cur[r]); + insertSXWoutputRgroupRow(Year, Iteration, r+1, RGroup_GetBiomass(r),getRGroupRelsize(r), RGroup[r]->pr, SXWResources->_resource_cur[r]/SXWResources->_bvt, _resource_cur[r]); } endTransaction(); } @@ -402,7 +399,7 @@ static void insertSXWoutputProdRow(int year, int iter, int Month, double BMass, void insertOutputProd(SW_VEGPROD *v) { int p; int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; beginTransaction(); int doy = 1; @@ -489,12 +486,12 @@ void insertRootsSum(RealD * _roots_active_sum) { int i; double m[12]; int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; beginTransaction(); ForEachVegType(i) { - for (l = 0; l < SXW.NTrLyrs; l++) { + for (l = 0; l < SXW->NTrLyrs; l++) { for (p = 0; p < 12; p++) { m[p] = _roots_active_sum[Itlp(i, l, p)]; } @@ -544,7 +541,7 @@ void insertRootsRelative(RealD * _roots_active_rel) { int nLyrs; double m[12]; int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; beginTransaction(); ForEachGroup(g) @@ -598,46 +595,46 @@ void insertTranspiration() { int p; double m[12]; int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; beginTransaction(); //Total - 0 - for (l = 0; l < SXW.NSoLyrs; l++) { + for (l = 0; l < SXW->NSoLyrs; l++) { for(p=0;p<12;p++) { - m[p] = SXW.transpTotal[Ilp(l, p)]; + m[p] = SXW->transpTotal[Ilp(l, p)]; } insertSXWoutputTranspirationRow(Year,Iteration,l+1,0,m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9],m[10],m[11]); } //Tree - 1 - for (l = 0; l < SXW.NSoLyrs; l++) { + for (l = 0; l < SXW->NSoLyrs; l++) { for(p=0;p<12;p++) { - m[p] = SXW.transpVeg[SW_TREES][Ilp(l, p)]; + m[p] = SXW->transpVeg[SW_TREES][Ilp(l, p)]; } insertSXWoutputTranspirationRow(Year,Iteration,l+1,1,m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9],m[10],m[11]); } //Shrub - 2 - for (l = 0; l < SXW.NSoLyrs; l++) { + for (l = 0; l < SXW->NSoLyrs; l++) { for(p=0;p<12;p++) { - m[p] = SXW.transpVeg[SW_SHRUB][Ilp(l, p)]; + m[p] = SXW->transpVeg[SW_SHRUB][Ilp(l, p)]; } insertSXWoutputTranspirationRow(Year,Iteration,l+1,2,m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9],m[10],m[11]); } //Grass - 3 - for (l = 0; l < SXW.NSoLyrs; l++) { + for (l = 0; l < SXW->NSoLyrs; l++) { for (p = 0; p < 12; p++) { - m[p] = SXW.transpVeg[SW_GRASS][Ilp(l, p)]; + m[p] = SXW->transpVeg[SW_GRASS][Ilp(l, p)]; } insertSXWoutputTranspirationRow(Year, Iteration, l+1, 3, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11]); } //Forb - 4 - for (l = 0; l < SXW.NSoLyrs; l++) { + for (l = 0; l < SXW->NSoLyrs; l++) { for (p = 0; p < 12; p++) { - m[p] = SXW.transpVeg[SW_FORBS][Ilp(l, p)]; + m[p] = SXW->transpVeg[SW_FORBS][Ilp(l, p)]; } insertSXWoutputTranspirationRow(Year, Iteration, l+1, 4, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11]); @@ -680,12 +677,12 @@ void insertSWCBulk() { int p; double m[12]; int Year = SW_Model.year; - int Iteration = Globals.currIter; + int Iteration = Globals->currIter; beginTransaction(); - for (l = 0; l < SXW.NSoLyrs; l++) { + for (l = 0; l < SXW->NSoLyrs; l++) { for(p=0;p<12;p++) { - m[p] = SXW.swc[Ilp(l, p)]; + m[p] = SXW->swc[Ilp(l, p)]; } insertSXWoutputSWCBulkRow(Year,Iteration,l+1,m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9],m[10],m[11]); } diff --git a/sxw_tester.c b/sxw_tester.c index 1498b9ff..333afed2 100644 --- a/sxw_tester.c +++ b/sxw_tester.c @@ -99,7 +99,7 @@ static void _print_results(void) { ForEachTrPeriod(pd) { LOG(fp,"%d", pd); ForEachTreeTranspLayer(lyr) - LOG(fp,"\t%5.4f", SXW.transpTotal[Ilp(lyr,pd)]); + LOG(fp,"\t%5.4f", SXW->transpTotal[Ilp(lyr,pd)]); LOG_NL; } @@ -165,7 +165,7 @@ static void _print_results(void) { sum = 0.; ForEachTreeTranspLayer(lyr) { sum += _roots_active[Iglp(g,lyr,pd)] - * SXW.transpTotal[Ilp(lyr,pd)]; + * SXW->transpTotal[Ilp(lyr,pd)]; } LOG(fp,"\t%5.4f", sum); } @@ -179,7 +179,7 @@ static void _read_test_data( void) { /*======================================================*/ /* Read a set of arbitrary (non-baseline) group sizes and * transpiration values and populates the RGroup[g].relsizes - * and the SXW.transp array. This simulates retrieval from + * and the SXW->transp array. This simulates retrieval from * soilwat. */ LyrIndex lyr, cnt; @@ -198,7 +198,7 @@ static void _read_test_data( void) { cnt=0; while( GetALine(fp, inbuf) ) { p = strtok(inbuf,", \t"); /* g'teed to work via GetALine() */ - if (++cnt > SXW.NPds) break; + if (++cnt > SXW->NPds) break; pd = atoi(p) -1; lyr = 0; @@ -208,20 +208,20 @@ static void _read_test_data( void) { "Compare with soil layer definitions for SOILWAT.", fname); } - SXW.transpTotal[Ilp(lyr,pd)] = atof(p); + SXW->transpTotal[Ilp(lyr,pd)] = atof(p); lyr++; } } - if (cnt > SXW.NPds) { + if (cnt > SXW->NPds) { LogError(logfp, LOGFATAL, "Too many time periods found in %s. Expected %d.", - fname, SXW.NPds); + fname, SXW->NPds); } - if (cnt < SXW.NPds) { + if (cnt < SXW->NPds) { LogError(logfp, LOGFATAL, "Not enough time periods found in %s. Expected %d.", - fname, SXW.NPds); + fname, SXW->NPds); } CloseFile(&fp); diff --git a/sxw_vars.h b/sxw_vars.h index 05a78975..0896c1cb 100644 --- a/sxw_vars.h +++ b/sxw_vars.h @@ -19,7 +19,7 @@ #include "generic.h" -extern SXW_t SXW; +extern SXW_t* SXW; #endif diff --git a/testing.sagebrush.master/Grid_Inputs/grid_disturbances.csv b/testing.sagebrush.master/Grid_Inputs/grid_disturbances.csv index 88f584aa..69e4defd 100644 --- a/testing.sagebrush.master/Grid_Inputs/grid_disturbances.csv +++ b/testing.sagebrush.master/Grid_Inputs/grid_disturbances.csv @@ -1,145 +1,17 @@ -cell,fecal_pat_use,ant_mound_use,animal_burrows_use,kill_yr,killfrq,extirp,killfreq_startyr,xgrow,veg_prod_type,grazing_frq,grazingfrq_startyr -0,0,0,0,3,0,0,0,0,2,3,4 -1,0,0,0,3,0,0,0,0,4,3,4 -2,0,0,0,3,0,0,0,0,4,3,4 -3,0,0,0,3,0,0,0,0,4,3,4 -4,0,0,0,3,0,0,0,0,4,3,4 -5,0,0,0,3,0,0,0,0,3,3,4 -6,0,0,0,3,0,0,0,0,3,3,4 -7,0,0,0,3,0,0,0,0,3,3,4 -8,0,0,0,3,0,0,0,0,2,3,4 -9,0,0,0,3,0,0,0,0,2,3,4 -10,0,0,0,3,0,0,0,0,2,3,4 -11,0,0,0,3,0,0,0,0,2,3,4 -12,0,0,0,3,0,0,0,0,2,3,4 -13,0,0,0,3,0,0,0,0,2,3,4 -14,0,0,0,3,0,0,0,0,2,3,4 -15,0,0,0,3,0,0,0,0,2,3,4 -16,0,0,0,3,0,0,0,0,2,3,4 -17,0,0,0,0,0,0,0,0,2,0,0 -18,0,0,0,0,0,0,0,0,2,0,0 -19,0,0,0,0,0,0,0,0,2,0,0 -20,0,0,0,0,0,0,0,0,2,0,0 -21,0,0,0,0,0,0,0,0,2,0,0 -22,0,0,0,0,0,0,0,0,2,0,0 -23,0,0,0,0,0,0,0,0,2,0,0 -24,0,0,0,0,0,0,0,0,2,0,0 -25,0,0,0,0,0,0,0,0,2,0,0 -26,0,0,0,0,0,0,0,0,2,0,0 -27,0,0,0,0,0,0,0,0,2,0,0 -28,0,0,0,0,0,0,0,0,2,0,0 -29,0,0,0,0,0,0,0,0,2,0,0 -30,0,0,0,0,0,0,0,0,2,0,0 -31,0,0,0,0,0,0,0,0,2,0,0 -32,0,0,0,0,0,0,0,0,2,0,0 -33,0,0,0,0,0,0,0,0,2,0,0 -34,0,0,0,0,0,0,0,0,2,0,0 -35,0,0,0,0,0,0,0,0,2,0,0 -36,0,0,0,0,0,0,0,0,2,0,0 -37,0,0,0,0,0,0,0,0,2,0,0 -38,0,0,0,0,0,0,0,0,2,0,0 -39,0,0,0,0,0,0,0,0,2,0,0 -40,0,0,0,0,0,0,0,0,2,0,0 -41,0,0,0,0,0,0,0,0,2,0,0 -42,0,0,0,0,0,0,0,0,2,0,0 -43,0,0,0,0,0,0,0,0,2,0,0 -44,0,0,0,0,0,0,0,0,2,0,0 -45,0,0,0,0,0,0,0,0,2,0,0 -46,0,0,0,0,0,0,0,0,2,0,0 -47,0,0,0,0,0,0,0,0,2,0,0 -48,0,0,0,0,0,0,0,0,2,0,0 -49,0,0,0,0,0,0,0,0,2,0,0 -50,0,0,0,0,0,0,0,0,2,0,0 -51,0,0,0,0,0,0,0,0,2,0,0 -52,0,0,0,0,0,0,0,0,2,0,0 -53,0,0,0,0,0,0,0,0,2,0,0 -54,0,0,0,0,0,0,0,0,2,0,0 -55,0,0,0,0,0,0,0,0,2,0,0 -56,0,0,0,0,0,0,0,0,2,0,0 -57,0,0,0,0,0,0,0,0,2,0,0 -58,0,0,0,0,0,0,0,0,2,0,0 -59,0,0,0,0,0,0,0,0,2,0,0 -60,0,0,0,0,0,0,0,0,2,0,0 -61,0,0,0,0,0,0,0,0,2,0,0 -62,0,0,0,0,0,0,0,0,2,0,0 -63,0,0,0,0,0,0,0,0,2,0,0 -64,0,0,0,0,0,0,0,0,2,0,0 -65,0,0,0,0,0,0,0,0,2,0,0 -66,0,0,0,0,0,0,0,0,2,0,0 -67,0,0,0,0,0,0,0,0,2,0,0 -68,0,0,0,0,0,0,0,0,2,0,0 -69,0,0,0,0,0,0,0,0,2,0,0 -70,0,0,0,0,0,0,0,0,2,0,0 -71,0,0,0,0,0,0,0,0,2,0,0 -72,0,0,0,0,0,0,0,0,2,0,0 -73,0,0,0,0,0,0,0,0,2,0,0 -74,0,0,0,0,0,0,0,0,2,0,0 -75,0,0,0,0,0,0,0,0,2,0,0 -76,0,0,0,0,0,0,0,0,2,0,0 -77,0,0,0,0,0,0,0,0,2,0,0 -78,0,0,0,0,0,0,0,0,2,0,0 -79,0,0,0,0,0,0,0,0,2,0,0 -80,0,0,0,0,0,0,0,0,2,0,0 -81,0,0,0,0,0,0,0,0,2,0,0 -82,0,0,0,0,0,0,0,0,2,0,0 -83,0,0,0,0,0,0,0,0,2,0,0 -84,0,0,0,0,0,0,0,0,2,0,0 -85,0,0,0,0,0,0,0,0,2,0,0 -86,0,0,0,0,0,0,0,0,2,0,0 -87,0,0,0,0,0,0,0,0,2,0,0 -88,0,0,0,0,0,0,0,0,2,0,0 -89,0,0,0,0,0,0,0,0,2,0,0 -90,0,0,0,0,0,0,0,0,2,0,0 -91,0,0,0,0,0,0,0,0,2,0,0 -92,0,0,0,0,0,0,0,0,2,0,0 -93,0,0,0,0,0,0,0,0,2,0,0 -94,0,0,0,0,0,0,0,0,2,0,0 -95,0,0,0,0,0,0,0,0,2,0,0 -96,0,0,0,0,0,0,0,0,2,0,0 -97,0,0,0,0,0,0,0,0,2,0,0 -98,0,0,0,0,0,0,0,0,2,0,0 -99,0,0,0,0,0,0,0,0,2,0,0 -100,0,0,0,0,0,0,0,0,2,0,0 -101,0,0,0,0,0,0,0,0,2,0,0 -102,0,0,0,0,0,0,0,0,2,0,0 -103,0,0,0,0,0,0,0,0,2,0,0 -104,0,0,0,0,0,0,0,0,2,0,0 -105,0,0,0,0,0,0,0,0,2,0,0 -106,0,0,0,0,0,0,0,0,2,0,0 -107,0,0,0,0,0,0,0,0,2,0,0 -108,0,0,0,0,0,0,0,0,2,0,0 -109,0,0,0,0,0,0,0,0,2,0,0 -110,0,0,0,0,0,0,0,0,2,0,0 -111,0,0,0,0,0,0,0,0,2,0,0 -112,0,0,0,0,0,0,0,0,2,0,0 -113,0,0,0,0,0,0,0,0,2,0,0 -114,0,0,0,0,0,0,0,0,2,0,0 -115,0,0,0,0,0,0,0,0,2,0,0 -116,0,0,0,0,0,0,0,0,2,0,0 -117,0,0,0,0,0,0,0,0,2,0,0 -118,0,0,0,0,0,0,0,0,2,0,0 -119,0,0,0,0,0,0,0,0,2,0,0 -120,0,0,0,0,0,0,0,0,2,0,0 -121,0,0,0,0,0,0,0,0,2,0,0 -122,0,0,0,0,0,0,0,0,2,0,0 -123,0,0,0,0,0,0,0,0,2,0,0 -124,0,0,0,0,0,0,0,0,2,0,0 -125,0,0,0,0,0,0,0,0,2,0,0 -126,0,0,0,0,0,0,0,0,2,0,0 -127,0,0,0,0,0,0,0,0,2,0,0 -128,0,0,0,0,0,0,0,0,2,0,0 -129,0,0,0,0,0,0,0,0,2,0,0 -130,0,0,0,0,0,0,0,0,2,0,0 -131,0,0,0,0,0,0,0,0,2,0,0 -132,0,0,0,0,0,0,0,0,2,0,0 -133,0,0,0,0,0,0,0,0,2,0,0 -134,0,0,0,0,0,0,0,0,2,0,0 -135,0,0,0,0,0,0,0,0,2,0,0 -136,0,0,0,0,0,0,0,0,2,0,0 -137,0,0,0,0,0,0,0,0,2,0,0 -138,0,0,0,0,0,0,0,0,2,0,0 -139,0,0,0,0,0,0,0,0,2,0,0 -140,0,0,0,0,0,0,0,0,2,0,0 -141,0,0,0,0,0,0,0,0,2,0,0 -142,0,0,0,0,0,0,0,0,2,0,0 -143,0,0,0,0,0,0,0,0,2,0,0 +cell,fecal_pat_use,ant_mound_use,animal_burrows_use,kill_yr,killfreq_startyr,Prescribed_killfreq,extirp,grazing_frq,grazingfrq_startyr,ignition +0,0,0,0,0,0,0,0,0,0,0 +1,0,0,0,0,5,80,0,0,0,0 +2,0,0,0,0,0,0,0,0,0,12.05 +3,0,0,0,0,1,100,0,0,0,0 +4,0,0,0,0,0,0,0,0,0,0 +5,0,0,0,0,0,0,0,0,0,0 +6,0,0,0,0,0,0,0,0,0,0 +7,0,0,0,0,0,0,0,0,0,0 +8,0,0,0,0,0,0,0,0,0,0 +9,0,0,0,0,0,0,0,0,0,0 +10,0,0,0,0,0,0,0,0,0,0 +11,0,0,0,0,0,0,0,0,0,0 +12,0,0,0,0,0,0,0,0,0,0 +13,0,0,0,0,0,0,0,0,0,0 +14,0,0,0,0,0,0,0,0,0,0 +15,0,0,0,0,0,0,0,0,0,0 diff --git a/testing.sagebrush.master/Grid_Inputs/grid_initSpecies.csv b/testing.sagebrush.master/Grid_Inputs/grid_initSpecies.csv index 4ad0ea15..e4a9c805 100644 --- a/testing.sagebrush.master/Grid_Inputs/grid_initSpecies.csv +++ b/testing.sagebrush.master/Grid_Inputs/grid_initSpecies.csv @@ -1 +1 @@ -cell,copy_cell,copy_which,use_SpinUp,artr,trdu,cryp,amre,chen,acmi,phho,arfr,lipu,brar,vuoc,spp1,spp2,pose,koma,bogr,spcr,gusa,chvi 0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0 1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5,1,0,0,,,,,,,,,,,,,,,,,,, 6,1,0,0,,,,,,,,,,,,,,,,,,, 7,1,0,0,,,,,,,,,,,,,,,,,,, 8,1,1,0,,,,,,,,,,,,,,,,,,, 9,1,1,0,,,,,,,,,,,,,,,,,,, 10,1,1,0,,,,,,,,,,,,,,,,,,, 11,1,1,0,,,,,,,,,,,,,,,,,,, 12,1,1,0,,,,,,,,,,,,,,,,,,, 13,1,1,0,,,,,,,,,,,,,,,,,,, 14,1,1,0,,,,,,,,,,,,,,,,,,, 15,1,2,0,,,,,,,,,,,,,,,,,,, 16,1,2,0,,,,,,,,,,,,,,,,,,, 17,1,2,0,,,,,,,,,,,,,,,,,,, 18,1,2,0,,,,,,,,,,,,,,,,,,, 19,1,2,0,,,,,,,,,,,,,,,,,,, 20,1,3,0,,,,,,,,,,,,,,,,,,, 21,1,3,0,,,,,,,,,,,,,,,,,,, 22,1,3,0,,,,,,,,,,,,,,,,,,, 23,1,3,0,,,,,,,,,,,,,,,,,,, 24,1,4,0,,,,,,,,,,,,,,,,,,, 25,1,4,0,,,,,,,,,,,,,,,,,,, 26,1,4,0,,,,,,,,,,,,,,,,,,, 27,1,4,0,,,,,,,,,,,,,,,,,,, 28,1,4,0,,,,,,,,,,,,,,,,,,, 29,1,4,0,,,,,,,,,,,,,,,,,,, 30,1,4,0,,,,,,,,,,,,,,,,,,, 31,1,4,0,,,,,,,,,,,,,,,,,,, 32,1,4,0,,,,,,,,,,,,,,,,,,, 33,1,4,0,,,,,,,,,,,,,,,,,,, 34,1,4,0,,,,,,,,,,,,,,,,,,, 35,1,4,0,,,,,,,,,,,,,,,,,,, 36,1,4,0,,,,,,,,,,,,,,,,,,, 37,1,4,0,,,,,,,,,,,,,,,,,,, 38,1,4,0,,,,,,,,,,,,,,,,,,, 39,1,4,0,,,,,,,,,,,,,,,,,,, 40,1,4,0,,,,,,,,,,,,,,,,,,, 41,1,4,0,,,,,,,,,,,,,,,,,,, 42,1,4,0,,,,,,,,,,,,,,,,,,, 43,1,4,0,,,,,,,,,,,,,,,,,,, 44,1,4,0,,,,,,,,,,,,,,,,,,, 45,1,4,0,,,,,,,,,,,,,,,,,,, 46,1,4,0,,,,,,,,,,,,,,,,,,, 47,1,4,0,,,,,,,,,,,,,,,,,,, 48,1,4,0,,,,,,,,,,,,,,,,,,, 49,1,4,0,,,,,,,,,,,,,,,,,,, 50,1,4,0,,,,,,,,,,,,,,,,,,, 51,1,4,0,,,,,,,,,,,,,,,,,,, 52,1,4,0,,,,,,,,,,,,,,,,,,, 53,1,4,0,,,,,,,,,,,,,,,,,,, 54,1,4,0,,,,,,,,,,,,,,,,,,, 55,1,4,0,,,,,,,,,,,,,,,,,,, 56,1,4,0,,,,,,,,,,,,,,,,,,, 57,1,4,0,,,,,,,,,,,,,,,,,,, 58,1,4,0,,,,,,,,,,,,,,,,,,, 59,1,4,0,,,,,,,,,,,,,,,,,,, 60,1,4,0,,,,,,,,,,,,,,,,,,, 61,1,4,0,,,,,,,,,,,,,,,,,,, 62,1,4,0,,,,,,,,,,,,,,,,,,, 63,1,4,0,,,,,,,,,,,,,,,,,,, 64,1,4,0,,,,,,,,,,,,,,,,,,, 65,1,4,0,,,,,,,,,,,,,,,,,,, 66,1,4,0,,,,,,,,,,,,,,,,,,, 67,1,4,0,,,,,,,,,,,,,,,,,,, 68,1,4,0,,,,,,,,,,,,,,,,,,, 69,1,4,0,,,,,,,,,,,,,,,,,,, 70,1,4,0,,,,,,,,,,,,,,,,,,, 71,1,4,0,,,,,,,,,,,,,,,,,,, 72,1,4,0,,,,,,,,,,,,,,,,,,, 73,1,4,0,,,,,,,,,,,,,,,,,,, 74,1,4,0,,,,,,,,,,,,,,,,,,, 75,1,4,0,,,,,,,,,,,,,,,,,,, 76,1,4,0,,,,,,,,,,,,,,,,,,, 77,1,4,0,,,,,,,,,,,,,,,,,,, 78,1,4,0,,,,,,,,,,,,,,,,,,, 79,1,4,0,,,,,,,,,,,,,,,,,,, 80,1,4,0,,,,,,,,,,,,,,,,,,, 81,1,4,0,,,,,,,,,,,,,,,,,,, 82,1,4,0,,,,,,,,,,,,,,,,,,, 83,1,4,0,,,,,,,,,,,,,,,,,,, 84,1,4,0,,,,,,,,,,,,,,,,,,, 85,1,4,0,,,,,,,,,,,,,,,,,,, 86,1,4,0,,,,,,,,,,,,,,,,,,, 87,1,4,0,,,,,,,,,,,,,,,,,,, 88,1,4,0,,,,,,,,,,,,,,,,,,, 89,1,4,0,,,,,,,,,,,,,,,,,,, 90,1,4,0,,,,,,,,,,,,,,,,,,, 91,1,4,0,,,,,,,,,,,,,,,,,,, 92,1,4,0,,,,,,,,,,,,,,,,,,, 93,1,4,0,,,,,,,,,,,,,,,,,,, 94,1,4,0,,,,,,,,,,,,,,,,,,, 95,1,4,0,,,,,,,,,,,,,,,,,,, 96,1,4,0,,,,,,,,,,,,,,,,,,, 97,1,4,0,,,,,,,,,,,,,,,,,,, 98,1,4,0,,,,,,,,,,,,,,,,,,, 99,1,4,0,,,,,,,,,,,,,,,,,,, 100,1,4,0,,,,,,,,,,,,,,,,,,, 101,1,4,0,,,,,,,,,,,,,,,,,,, 102,1,4,0,,,,,,,,,,,,,,,,,,, 103,1,4,0,,,,,,,,,,,,,,,,,,, 104,1,4,0,,,,,,,,,,,,,,,,,,, 105,1,4,0,,,,,,,,,,,,,,,,,,, 106,1,4,0,,,,,,,,,,,,,,,,,,, 107,1,4,0,,,,,,,,,,,,,,,,,,, 108,1,4,0,,,,,,,,,,,,,,,,,,, 109,1,4,0,,,,,,,,,,,,,,,,,,, 110,1,4,0,,,,,,,,,,,,,,,,,,, 111,1,4,0,,,,,,,,,,,,,,,,,,, 112,1,4,0,,,,,,,,,,,,,,,,,,, 113,1,4,0,,,,,,,,,,,,,,,,,,, 114,1,4,0,,,,,,,,,,,,,,,,,,, 115,1,4,0,,,,,,,,,,,,,,,,,,, 116,1,4,0,,,,,,,,,,,,,,,,,,, 117,1,4,0,,,,,,,,,,,,,,,,,,, 118,1,4,0,,,,,,,,,,,,,,,,,,, 119,1,4,0,,,,,,,,,,,,,,,,,,, 120,1,4,0,,,,,,,,,,,,,,,,,,, 121,1,4,0,,,,,,,,,,,,,,,,,,, 122,1,4,0,,,,,,,,,,,,,,,,,,, 123,1,4,0,,,,,,,,,,,,,,,,,,, 124,1,4,0,,,,,,,,,,,,,,,,,,, 125,1,4,0,,,,,,,,,,,,,,,,,,, 126,1,4,0,,,,,,,,,,,,,,,,,,, 127,1,4,0,,,,,,,,,,,,,,,,,,, 128,1,4,0,,,,,,,,,,,,,,,,,,, 129,1,4,0,,,,,,,,,,,,,,,,,,, 130,1,4,0,,,,,,,,,,,,,,,,,,, 131,1,4,0,,,,,,,,,,,,,,,,,,, 132,1,4,0,,,,,,,,,,,,,,,,,,, 133,1,4,0,,,,,,,,,,,,,,,,,,, 134,1,4,0,,,,,,,,,,,,,,,,,,, 135,1,4,0,,,,,,,,,,,,,,,,,,, 136,1,4,0,,,,,,,,,,,,,,,,,,, 137,1,4,0,,,,,,,,,,,,,,,,,,, 138,1,4,0,,,,,,,,,,,,,,,,,,, 139,1,4,0,,,,,,,,,,,,,,,,,,, 140,1,4,0,,,,,,,,,,,,,,,,,,, 141,1,4,0,,,,,,,,,,,,,,,,,,, 142,1,4,0,,,,,,,,,,,,,,,,,,, 143,1,4,0,,,,,,,,,,,,,,,,,,, \ No newline at end of file +cell,copy_cell,copy_which,artr,trdu,cryp,amre,chen,acmi,phho,arfr,lipu,brar,vuoc,spp1,spp2,pose,koma,bogr,spcr,gusa,chvi 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 5,1,0,,,,,,,,,,,,,,,,,,, 6,1,0,,,,,,,,,,,,,,,,,,, 7,1,0,,,,,,,,,,,,,,,,,,, 8,1,1,,,,,,,,,,,,,,,,,,, 9,1,1,,,,,,,,,,,,,,,,,,, 10,1,1,,,,,,,,,,,,,,,,,,, 11,1,1,,,,,,,,,,,,,,,,,,, 12,1,1,,,,,,,,,,,,,,,,,,, 13,1,1,,,,,,,,,,,,,,,,,,, 14,1,1,,,,,,,,,,,,,,,,,,, 15,1,2,,,,,,,,,,,,,,,,,,, \ No newline at end of file diff --git a/testing.sagebrush.master/Grid_Inputs/grid_seed_dispersal.in b/testing.sagebrush.master/Grid_Inputs/grid_seed_dispersal.in deleted file mode 100644 index 3bcbe2bb..00000000 --- a/testing.sagebrush.master/Grid_Inputs/grid_seed_dispersal.in +++ /dev/null @@ -1,20 +0,0 @@ -# Seed dispersal setup for STEPWAT grid version - DLM 07-29-13. This file contains constants that are used in seed dispersal. The rest of the seed dispersal inputs are set up on a species basis in the species input file. - -#CONSTANTS from the max distance function: MAXD = (H * VW) / VT. MAXD refers to the maximum distance that a seed can be dispersed to. If you're MAXD ends up being really small, then you can get kinda weird results, so be careful. -#30.0 # H - the average release height of the inflorescences (30 cm in the paper) -500.0 # VW - the mean horizontal wind speed (500 cm/sec in the paper) -#100.0 # VT - the average sinking velocity of the seeds (100 cm/sec in the paper) - -#SEED DISPERSAL OUTPUTS -1 # output seed dispersal (ie. the total probability that a cell received seeds for each cell for each year for each species)? 1 means yes, 0 means no -1 # output header (ie. the names of all the species)? 1 means yes, 0 means no. Suggested: yes, as it's hard to figure out what all the numbers mean elsewise. -, # output seperator... specify one of the following as a separator: t = tab, s = space, or any single character such as , | : etc (excluding '#','t', and 's'). Suggested: tab. - -#Spinup and Seed Availability options -#NOTE: options 1a, 2a, and Xb are mutually exclusive. Options 1b and 2b can be combined. Cells can be empty of plants. -10 # option 1) number of years N at the beginning of the simulation during which seeds are available for germination. Input: N years. -0 # option 1a) all cells and species. 1 means yes, 0 means no. -0 # option 1b) input for each cell: seeds of which species are available during those first N years [names & order of all species in species.in]. 1 means yes, 0 means no. -# option 2) run one site without dispersal (ie, conditions of 1-site StepWat, ie, seeds available in every cell for every year) for inputted # of years x replications (eg, 500 years times 10 replications) as spinup -1 # option 2a) use this spinup as init condition in all cells. 1 means yes, 0 means no. -0 # option 2b) input for each cell whether or not to use this spinup as inits. 1 means yes, 0 means no. diff --git a/testing.sagebrush.master/Grid_Inputs/grid_setup.in b/testing.sagebrush.master/Grid_Inputs/grid_setup.in index 70fac3bd..b69a3860 100644 --- a/testing.sagebrush.master/Grid_Inputs/grid_setup.in +++ b/testing.sagebrush.master/Grid_Inputs/grid_setup.in @@ -3,4 +3,11 @@ 2 2 # rows cols 1 # use disturbances csv file (0 or 1)... 0 means no, 1 means yes 1 # use soils csv file (0 or 1)... 0 means no, 1 means yes -1 # use seed dispersal (0 or 1)... 0 means no, 1 means yes +0 # use seed dispersal (0 or 1)... 0 means no, 1 means yes +spinup # Initialization method. Options are "spinup", "seeds", or "none" +300 # Number of years to perform initialization (whichever method you choose). +1 # Write separate output files for each cell. + +#SEED DISPERSAL OUTPUTS +1 # output seed dispersal summary file? 1 means yes, 0 means no +, # output seperator. Valid options are: t = tab, s = space, or any single character such as , | : etc (excluding '#','t', and 's'). Suggested: tab. diff --git a/testing.sagebrush.master/Grid_Inputs/grid_soils.csv b/testing.sagebrush.master/Grid_Inputs/grid_soils.csv old mode 100644 new mode 100755 index efe52634..c8ecc4b7 --- a/testing.sagebrush.master/Grid_Inputs/grid_soils.csv +++ b/testing.sagebrush.master/Grid_Inputs/grid_soils.csv @@ -1 +1,31 @@ -cell,copy_cell,copy_which,num_layers,sxw_roots,1_depth,1_matricd,1_gravel_content,1_evco,1_trco_grass,1_trco_shrub,1_trco_tree,1_trco_forb,1_sand,1_clay,1_imperm,1_soiltemp,2_depth,2_matricd,2_gravel_content,2_evco,2_trco_grass,2_trco_shrub,2_trco_tree,2_trco_forb,2_sand,2_clay,2_imperm,2_soiltemp,3_depth,3_matricd,3_gravel_content,3_evco,3_trco_grass,3_trco_shrub,3_trco_tree,3_trco_forb,3_sand,3_clay,3_imperm,3_soiltemp,4_depth,4_matricd,4_gravel_content,4_evco,4_trco_grass,4_trco_shrub,4_trco_tree,4_trco_forb,4_sand,4_clay,4_imperm,4_soiltemp,5_depth,5_matricd,5_gravel_content,5_evco,5_trco_grass,5_trco_shrub,5_trco_tree,5_trco_forb,5_sand,5_clay,5_imperm,5_soiltemp,6_depth,6_matricd,6_gravel_content,6_evco,6_trco_grass,6_trco_shrub,6_trco_tree,6_trco_forb,6_sand,6_clay,6_imperm,6_soiltemp,7_depth,7_matricd,7_gravel_content,7_evco,7_trco_grass,7_trco_shrub,7_trco_tree,7_trco_forb,7_sand,7_clay,7_imperm,7_soiltemp,8_depth,8_matricd,8_gravel_content,8_evco,8_trco_grass,8_trco_shrub,8_trco_tree,8_trco_forb,8_sand,8_clay,8_imperm,8_soiltemp,9_depth,9_matricd,9_gravel_content,9_evco,9_trco_grass,9_trco_shrub,9_trco_tree,9_trco_forb,9_sand,9_clay,9_imperm,9_soiltemp 0,0,0,8,sxwroots1.in,5,1.43,0,0.812,0.169,0.169,0.169,0.169,0.51,0.15,0,0.186,10,1.41,0,0.153,0.173,0.173,0.173,0.173,0.44,0.26,0,0.372,20,1.39,0,0.034,0.339,0.339,0.339,0.339,0.35,0.41,0,0.744,30,1.39,0,0,0.186,0.186,0.186,0.186,0.32,0.45,0,1.116,40,1.38,0,0,0.133,0.133,0.133,0.133,0.31,0.47,0,1.488,60,1.15,0,0,0,0.1,0,0,0.32,0.47,0,2.232,80,1.31,0,0,0,0,0,0,0.57,0.28,0,2.975,85,1.31,0,0,0,0,0,0,0.57,0.28,0,2.975,,,,,,,,,,,, 1,0,0,9,sxwroots2.in,5,1.43,0,0.812,0.169,0.169,0.169,0.169,0.51,0.15,0,0.186,10,1.41,0,0.153,0.173,0.173,0.173,0.173,0.44,0.26,0,0.372,20,1.39,0,0.034,0.339,0.239,0.339,0.339,0.35,0.41,0,0.744,30,1.39,0,0,0.186,0.186,0.186,0.186,0.32,0.45,0,1.116,40,1.38,0,0,0.133,0.133,0.133,0.133,0.31,0.47,0,1.488,60,1.15,0,0,0,0.1,0,0,0.32,0.47,0,2.232,80,1.31,0,0,0,0,0,0,0.57,0.28,0,2.975,85,1.31,0,0,0,0,0,0,0.57,0.28,0,2.975,90,1.31,0,0,0,0,0,0,0.57,0.28,0,2.975 2,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 3,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 4,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 5,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 6,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 7,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 8,1,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, \ No newline at end of file +cell,copy_cell,num_layers,layer,depth,matricd,gravel_content,evco,trco_grass,trco_shrub,trco_tree,trco_forb,sand,clay,imperm,soiltemp,sxw_roots +0,,8,1,10,1.43,0,0.5,0.1,0.1,0.1,0.1,0.45,0.18,0,0.186,sxwroots1.in +0,,8,2,20,1.41,0,0.35,0.25,0.25,0.25,0.25,0.48,0.19,0,0.372,sxwroots1.in +0,,8,3,30,1.39,0,0.15,0.3,0.3,0.3,0.3,0.53,0.16,0,0.744,sxwroots1.in +0,,8,4,40,1.39,0,0,0.2,0.2,0.2,0.2,0.53,0.16,0,1.116,sxwroots1.in +0,,8,5,60,1.38,0,0,0.1,0.1,0.1,0.1,0.53,0.16,0,1.488,sxwroots1.in +0,,8,6,80,1.15,0,0,0.05,0.05,0.05,0.05,0.53,0.16,0,2.232,sxwroots1.in +0,,8,7,100,1.31,0,0,0,0,0,0,0.53,0.16,0,2.975,sxwroots1.in +0,,8,8,150,1.31,0,0,0,0,0,0,0.53,0.16,0,2.975,sxwroots1.in +1,,8,1,10,1.43,0,0.5,0.1,0.1,0.1,0.1,0.45,0.18,0,0.186,sxwroots2.in +1,,8,2,20,1.41,0,0.35,0.25,0.25,0.25,0.25,0.48,0.19,0,0.372,sxwroots2.in +1,,8,3,30,1.39,0,0.15,0.3,0.3,0.3,0.3,0.53,0.16,0,0.744,sxwroots2.in +1,,8,4,40,1.39,0,0,0.2,0.2,0.2,0.2,0.53,0.16,0,1.116,sxwroots2.in +1,,8,5,60,1.38,0,0,0.1,0.1,0.1,0.1,0.53,0.16,0,1.488,sxwroots2.in +1,,8,6,80,1.15,0,0,0.05,0.05,0.05,0.05,0.53,0.16,0,2.232,sxwroots2.in +1,,8,7,100,1.31,0,0,0,0,0,0,0.53,0.16,0,2.975,sxwroots2.in +1,,8,8,150,1.31,0,0,0,0,0,0,0.49,0.2,0,2.975,sxwroots2.in +2,0,,,,,,,,,,,,,,, +3,1,,,,,,,,,,,,,,, +4,0,,,,,,,,,,,,,,, +5,1,,,,,,,,,,,,,,, +6,0,,,,,,,,,,,,,,, +7,1,,,,,,,,,,,,,,, +8,0,,,,,,,,,,,,,,, +9,1,,,,,,,,,,,,,,, +10,0,,,,,,,,,,,,,,, +11,1,,,,,,,,,,,,,,, +12,0,,,,,,,,,,,,,,, +13,1,,,,,,,,,,,,,,, +14,0,,,,,,,,,,,,,,, +15,1,,,,,,,,,,,,,,, diff --git a/testing.sagebrush.master/Stepwat_Inputs/Input/species.in b/testing.sagebrush.master/Stepwat_Inputs/Input/species.in index cef4610f..05704b46 100644 --- a/testing.sagebrush.master/Stepwat_Inputs/Input/species.in +++ b/testing.sagebrush.master/Stepwat_Inputs/Input/species.in @@ -171,29 +171,30 @@ # Pmax = probability of producing seeds in a wet year # H = the average release height of the inflorescences (cm) # VT = the average sinking velocity of the seeds (cm/sec) +# VW - the mean horizontal wind speed (500 cm/sec in Coffin and Lauenroth 1989) # -# name dispersal param1 PPTdry PPTwet Pmin Pmax H VT - artr 1 0.5 105 520 0.01 0.55 30.0 100.0 - trdu 1 0.5 105 520 0.01 0.55 30.0 100.0 - cryp 1 0.5 105 520 0.01 0.55 30.0 100.0 - amre 1 0.5 105 520 0.01 0.55 30.0 100.0 - chen 1 0.5 105 520 0.01 0.55 30.0 100.0 - acmi 1 0.5 105 520 0.01 0.55 30.0 100.0 - phho 1 0.5 105 520 0.01 0.55 30.0 100.0 - arfr 1 0.5 105 520 0.01 0.55 30.0 100.0 - lipu 1 0.5 105 520 0.01 0.55 30.0 100.0 - brte 1 0.5 105 520 0.01 0.55 30.0 100.0 - vuoc 1 0.5 105 520 0.01 0.55 30.0 100.0 - pssp 1 0.5 105 520 0.01 0.55 30.0 100.0 - koma 1 0.5 105 520 0.01 0.55 30.0 100.0 - bogr 1 0.5 105 520 0.01 0.55 30.0 100.0 - spcr 1 0.5 105 520 0.01 0.55 30.0 100.0 - gusa 1 0.5 105 520 0.01 0.55 30.0 100.0 - chvi 1 0.5 105 520 0.01 0.55 30.0 100.0 - oppo 1 0.5 105 520 0.01 0.55 30.0 100.0 +# name dispersal param1 PPTdry PPTwet Pmin Pmax H VT VW + artr 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + trdu 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + cryp 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + amre 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + chen 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + acmi 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + phho 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + arfr 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + lipu 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + brte 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + vuoc 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + pssp 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + koma 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + bogr 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + spcr 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + gusa 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + chvi 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 + oppo 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 -#spp1 1 0.5 105 520 0.01 0.55 30.0 100.0 -#spp2 1 0.5 105 520 0.01 0.55 30.0 100.0 +#spp1 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 +#spp2 1 0.5 105 520 0.01 0.55 30.0 100.0 500.0 [end] # this marks the end of the seed-dispersal parameters diff --git a/testing.sagebrush.master/files.in b/testing.sagebrush.master/files.in index 243fc5ff..f87545b5 100644 --- a/testing.sagebrush.master/files.in +++ b/testing.sagebrush.master/files.in @@ -7,12 +7,13 @@ g_logfile.log # name of logfile (can also be stdout) Grid_Inputs/grid_setup.in # name of grid setup file Grid_Inputs/grid_disturbances.csv # name of grid disturbances input file Grid_Inputs/grid_soils.csv # name of grid soils input file -Grid_Inputs/grid_seed_dispersal.in # name of grid seed dispersal setup file Grid_Inputs/grid_initSpecies.csv # name of grid species input file files.in # name of stepwat files.in file +Input/maxrgroupspecies.in # name of stepwat maxrgroupspecies.in file Output/g_bmassavg # name of the prefix given to the biomass output files Output/g_mortavg # name of the prefix given to the mortuary output files Output/g_receivedprob # name of the prefix given to the seed disperal received probability output files Output/g_bmass_cell_avg # name of the prefix given to the biomass grid cell avg output files +Output/g_mort_cell_avg # name of the prefix given to the mortality grid cell avg output files diff --git a/testing.sagebrush.master/readme.txt b/testing.sagebrush.master/readme.txt deleted file mode 100644 index 529ba7ec..00000000 --- a/testing.sagebrush.master/readme.txt +++ /dev/null @@ -1,3 +0,0 @@ -#By Kyle Palmquist, 06/01/2015 -#This folder contains all of the default input parameters for the sagebrush steppe in Montana (based on Trace Martyn’s data). -#The weather data and site parameters are for Lewistown, MT. \ No newline at end of file