-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathST_grid.c
2219 lines (1960 loc) · 73.9 KB
/
ST_grid.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* \file ST_grid.c
* \brief Function definitions for the gridded mode.
*
* 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 three additional features: [spinup](\ref SPINUP),
* [seed dispersal](\ref SEED_DISPERSAL) and [colonization](\ref COLONIZATION).
* Spinup allows vegetation to establish before the simulation
* experiments begin. Seed dispersal allows each cell to disperse seeds to
* nearby cells.
*
* See issue #262 and pull request #375 on GitHub for a discussion of the
* overhaul of this module.
*
* \author DLM (initial programming)
* \author Fredrick Pierson
* \author Chandler Haukap
* \date March through July 2019
* \ingroup GRID_PRIVATE
*/
/*******************************************************/
/* -------------- INCLUDES / DEFINES ----------------- */
/*******************************************************/
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <stdlib.h>
#include "sw_src/include/generic.h"
#include "sw_src/include/filefuncs.h"
#include "sw_src/include/myMemory.h"
#include "sw_src/include/rands.h"
#include "sw_src/include/SW_SoilWater.h"
#include "sw_src/include/SW_Weather.h"
#include "sw_src/include/SW_Markov.h"
#include "ST_grid.h"
#include "ST_steppe.h"
#include "ST_globals.h" // externs `UseProgressBar`
#include "ST_functions.h" // externs `environs_rng`, `resgroups_rng`, `species_rng`
#include "ST_stats.h"
#include "sxw_funcs.h"
#include "ST_spinup.h"
#include "ST_progressBar.h"
#include "ST_colonization.h"
#include "ST_seedDispersal.h" // externs `UseSeedDispersal`
#include "ST_mortality.h" // externs `mortality_rng`, `*_SomeKillage`, `UseWildfire`
#include "sw_src/include/SW_Output.h"
#include "sw_src/include/SW_Output_outtext.h"
#include "sw_src/include/SW_Output_outarray.h"
#include "sw_src/include/SW_Flow.h" // for `SW_FLW_init_run()`
#include "sw_src/include/SW_Flow_lib.h" // for `SW_ST_init_run()`
/* =================================================== */
/* Global Variables */
/* --------------------------------------------------- */
char sd_Sep;
int grid_Cells = 0;
Bool UseDisturbances = 0, UseSoils = 0, sd_DoOutput = 0; //these are treated like booleans
sw_random_t grid_rng; // Gridded mode's unique RNG.
/**
* \brief The main struct of the gridded mode module.
*
* gridCells[i][j] denotes the cell at position (i,j)
*
* \author Chandler Haukap
* \ingroup GRID
*/
CellType** gridCells;
/**
* \brief Rows in the [grid](\ref gridCells).
* \ingroup GRID
*/
int grid_Rows = 0;
/**
* \brief Columns in the [grid](\ref gridCells).
* \ingroup GRID
*/
int grid_Cols = 0;
/**
* \brief Array of file names. Use the \ref File_Indices enum to pick the
* correct index.
* \ingroup GRID
*/
char *grid_files[N_GRID_FILES];
/** \brief Array of directory names. Use the \ref Directory_Indices enum to
* pick the correct index.
* \ingroup GRID
*/
char *grid_directories[N_GRID_DIRECTORIES];
/**
* \brief TRUE if every cell should write its own output file.
* \ingroup GRID
*/
Bool writeIndividualFiles = 0;
/**
* \brief Set to TRUE to tell the gridded mode to output SOILWAT2 files.
* \ingroup GRID
*/
Bool writeSOILWAT2Output = 0;
/******** Modular External Function Declarations ***********/
/* -- truly global functions are declared in functions.h --*/
/***********************************************************/
//from ST_species.c
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 copy_rgroup(const GroupType* src, GroupType* dest);
//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 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);
/***********************************************************/
/* --------- Locally Used Function Declarations ---------- */
/***********************************************************/
void _copy_soils(SoilType* src, SoilType* dest);
static void printGeneralInfo(void);
static void _init_grid_files(void);
static void _init_SXW_inputs(Bool init_SW, char *f_roots);
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 int _read_soil_line(char* buf, SoilType* destination, int layer);
static void _read_spinup_species(void);
static void _read_maxrgroupspecies(void);
static void _read_grid_setup(void);
static void _read_files(void);
static void _init_soilwat_outputs(char* fileName);
static void _init_stepwat_inputs(void);
static void _init_grid_inputs(void);
static void _separateSOILWAT2Output(void);
static void _separateSOILWAT2DailyOutput(char* fileName, int* cellNumbers);
static void _separateSOILWAT2MonthlyOutput(char* fileName, int* cellNumbers);
static void _separateSOILWAT2YearlyOutput(char* fileName, int* cellNumbers);
static int _getNumberSOILWAT2OutputCells(void);
static int* _getSOILWAT2OutputCells(void);
/******************** Begin Model Code *********************/
/***********************************************************/
/**
* \brief Print information about the simulation to stdout.
*
* \author Chandler Haukap
* \date August 2019
* \ingroup GRID
*/
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(shouldSpinup){
printf("Number of spinup years: %d\n", SuperGlobals.runSpinupYears);
}
if(UseSeedDispersal){
printf("Dispersing seeds between cells\n");
}
printf("\n");
/* --------------------------- END printing general info -------------------------------- */
}
/**
* \brief Run gridded mode.
*
* This function is responsible for initializing the [cells](\ref CellType),
* running the simulation on all of them, then printing output.
*
* \sideeffect
* In theory this function will have no side effects, but memory leaks are
* possible due to the massive amount of allocations associated with
* gridded mode.
*
* \author Chandler Haukap
* \date August 2019
* \ingroup GRID
*/
void runGrid(void)
{
int i, j;
Bool killedany;
IntS year, iter;
if(SuperGlobals.storeAllIterations) {
printf("WARNING: SOILWAT2 iteration output unavailable for gridded mode.\n");
SuperGlobals.storeAllIterations = FALSE;
}
_init_grid_files(); // reads in files.in file
_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
initColonization(grid_files[GRID_FILE_COLONIZATION]);
//SWC hist file prefix needs to be cleared
free(SoilWatRun.SoilWat.hist.file_prefix);
SoilWatRun.SoilWat.hist.file_prefix = NULL;
printGeneralInfo();
if(shouldSpinup){
runSpinup();
} 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, TRUE);
ChDir("..");
}
// SOILWAT resets SoilWatRun.Weather.name_prefix every iteration. This is not the behavior we want
// so the name is stored here.
char SW_prefix_permanent[MAX_FILENAMESIZE - 5]; // see `SW_WEATHER`: subtract 4-digit 'year' file type extension
sprintf(SW_prefix_permanent, "%s/%s",
grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS],
SoilWatRun.Weather.name_prefix);
_init_soilwat_outputs(grid_files[GRID_FILE_SOILWAT2_OUTPUT]);
SW_OUT_set_ncol(SoilWatDomain.nMaxSoilLayers, SoilWatDomain.nMaxEvapLayers,
SoilWatRun.VegEstab.count, SoilWatDomain.OutDom.ncol_OUT,
SoilWatDomain.OutDom.nvar_OUT, SoilWatDomain.OutDom.nsl_OUT,
SoilWatDomain.OutDom.npft_OUT); // set number of output columns
SW_OUT_set_colnames(SoilWatRun.Site.n_layers, SoilWatRun.VegEstab.parms,
SoilWatDomain.OutDom.ncol_OUT,
SoilWatDomain.OutDom.colnames_OUT, &LogInfo); // set column names for output files
if (_getNumberSOILWAT2OutputCells() > 0) {
SW_OUT_create_summary_files(&SoilWatDomain.OutDom, &SoilWatRun.FileStatus,
SoilWatDomain.PathInfo.InFiles, SoilWatRun.Site.n_layers,
&LogInfo);
SW_OUT_construct_outarray(&SoilWatDomain.OutDom, &SoilWatRun.OutRun, &LogInfo);
}
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(SoilWatRun.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 = SoilWatRun.OutRun.currIter = iter;
if (_getNumberSOILWAT2OutputCells() > 0) {
SoilWatDomain.OutDom.print_IterationSummary =
(Bool) (Globals->currIter == SuperGlobals.runModelIterations);
}
}
}
unload_cell(); // Reset the global variables
// If we used spinup we need to reset to the state of the program right after spinup.
if (shouldSpinup){
loadSpinupConditions();
}
for (year = 1; year <= SuperGlobals.runModelYears; year++)
{ //for each year
if(UseProgressBar){
logProgress(iter, year, SIMULATION);
}
if (UseSeedDispersal){
disperseSeeds(year);
}
// Allow the colonization module to run. This function MUST be
// Called after disperseSeeds() because it modifies the
// seedsPresent variable of each Species.
colonize(year);
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);
//printf("------------------------Repetition/year = %d / %d\n", iter, year);
set_all_rngs(SuperGlobals.randseed, iter, year, j * grid_Rows + i);
Globals->currYear = year;
/* The following functions mimic ST_main.c. */
rgroup_Establish(); // Establish individuals.
Env_Generate(); // Run SOILWAT2 to generate resources.
rgroup_PartResources(); // Distribute resources
rgroup_Grow(); // Implement plant growth
mort_Main(&killedany); // Mortality that occurs during the growing season
rgroup_IncrAges(); // Increment ages of all plants
grazing_EndOfYear(); // Livestock grazing
save_annual_species_relsize(); // Save annuals before we kill them
mort_EndOfYear(); // End of year mortality.
stat_Collect(year); // Update the accumulators
killAnnuals(); // Kill annuals
killMaxage(); // Kill plants that reach max age
proportion_Recovery(); // Recover from any disturbances
killExtraGrowth(); // Kill superfluous growth
} /* end model run for this cell*/
} /* end model run for this row */
unload_cell(); // Reset the global variables
}/* end model run for this year*/
// 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);
stat_Collect_GMort();
stat_Collect_SMort();
}
}
}
unload_cell();
//reset soilwat to initial condition
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);
int realYears = SuperGlobals.runModelYears;
SuperGlobals.runModelYears *= _getNumberSOILWAT2OutputCells();
SXW_Reset(gridCells[i][j].mySXW->f_watin, FALSE);
unload_cell();
SuperGlobals.runModelYears = realYears;
}
}
free(SoilWatRun.SoilWat.hist.file_prefix);
SoilWatRun.SoilWat.hist.file_prefix = NULL;
ChDir("..");
} /* end iterations */
if(UseProgressBar){
logProgress(0, 0, OUTPUT);
}
// 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 * grid_Cols);
load_cell(i, j);
char fileMort[1024], fileBMass[1024];
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 && writeIndividualFiles){
stat_Output_AllMorts();
}
if (BmassFlags.summary && writeIndividualFiles){
stat_Output_AllBmass();
}
}
}
unload_cell(); // Reset the global variables
if (recordDispersalEvents){
outputDispersalEvents(grid_files[GRID_FILE_PREFIX_DISPERSALEVENTS]);
}
// 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);
}
// If the user requested SOILWAT2 output this function will separate the
// output into cell-specific files. If they didn't request SOILWAT2 output
// this function will do nothing.
_separateSOILWAT2Output();
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
freeColonizationMemory(); // Free memory allocated to the Colonization module.
freeDispersalMemory(); // Free memory allocated to the Seed Dispersal module.
if(shouldSpinup) {
freeSpinupMemory();
}
logProgress(0, 0, DONE);
}
/**
* \brief Read the files.in file.
*
* The files.in file specifies the locations of the other input files.
*
* \sideeffect
* This function saves the file names it reads to \ref grid_files and
* \ref grid_directories.
*
* \ingroup GRID_PRIVATE
*/
static void _init_grid_files(void)
{
// reads the files.in file
FILE *f;
char buf[1024];
int i;
f = OpenFile(Parm_name(F_First), "r", &LogInfo);
for (i = 0; i < N_GRID_DIRECTORIES; i++)
{ //0 is stepwat directory
if (!GetALine(f, buf, 1024))
break;
grid_directories[i] = Str_Dup(Str_TrimLeftQ(buf), &LogInfo);
}
if (i != N_GRID_DIRECTORIES)
LogError(&LogInfo, LOGERROR, "Invalid files.in");
for (i = 0; i < N_GRID_FILES; i++)
{
if (!GetALine(f, buf, 1024))
break;
grid_files[i] = Str_Dup(Str_TrimLeftQ(buf), &LogInfo);
}
if (i != N_GRID_FILES)
LogError(&LogInfo, LOGERROR, "Invalid files.in");
// opens the log file...
if (!strcmp("stdout", grid_files[GRID_FILE_LOGFILE])){
LogInfo.logfp = stdout;
}
else {
LogInfo.logfp = OpenFile(grid_files[GRID_FILE_LOGFILE], "w", &LogInfo);
}
CloseFile(&f, &LogInfo);
}
/**
* \brief Read all gridded mode files excluding grid_setup.in.
*
* All associated fields will be populated with the values read.
*
* \sideeffect
* This function overrides values in the \ref RGroup and \ref Species
* arrays so make sure you have read the non-gridded mode files before
* calling this function.
*
* \ingroup GRID_PRIVATE
*/
static void _init_grid_inputs(void)
{
int i, j;
if (UseDisturbances){
_read_disturbances_in();
}
if(shouldSpinup){
_read_spinup_species();
}
if (UseSoils) {
_read_soils_in();
}
for(i = 0; i < grid_Rows; ++i) {
for(j = 0; j < grid_Cols; ++j) {
gridCells[i][j].DuringSpinup = FALSE;
}
}
}
/**
* \brief Read \ref SXW input files
*
* \ingroup GRID
*/
static void _init_SXW_inputs(Bool init_SW, char *f_roots)
{
int realYears = SuperGlobals.runModelYears;
SuperGlobals.runModelYears *= (grid_Cols * grid_Rows);
SXW_Init(init_SW, f_roots); // initializes soilwat
SuperGlobals.runModelYears = realYears;
if (init_SW)
{
char aString[2048];
sprintf(aString, "%s/%s", grid_directories[GRID_DIRECTORY_STEPWAT_INPUTS], SoilWatRun.Weather.name_prefix);
sprintf(SoilWatRun.Weather.name_prefix, "%s", aString); //updates the directory correctly for the weather files so soilwat can find them
}
}
static void _init_soilwat_outputs(char* fileName) {
if(!writeSOILWAT2Output) {
return;
}
char buffer[2048];
int cell;
FILE* inFile = fopen(fileName, "r");
if(!inFile) {
LogError(&LogInfo, LOGERROR, "Could not open SOILWAT2 output cells file."
"\n\tFile named \"%s\"", fileName);
}
if(!GetALine(inFile, buffer, 2048)) {
fclose(inFile);
return;
}
while(sscanf(buffer, "%d,%s", &cell, buffer) == 2) {
if(cell < 0 || cell > (grid_Cols * grid_Rows)) {
LogError(&LogInfo, LOGWARN, "Invalid cell (%d) specified in file \"%s\"",
cell, fileName);
}
gridCells[cell / grid_Cols][cell % grid_Cols].generateSWOutput = TRUE;
}
if(sscanf(buffer, "%d", &cell) == 1) {
if(cell < 0 || cell > (grid_Cols * grid_Rows)) {
LogError(&LogInfo, LOGWARN, "Invalid cell (%d) specified in file \"%s\"",
cell, fileName);
}
gridCells[cell / grid_Cols][cell % grid_Cols].generateSWOutput = TRUE;
}
fclose(inFile);
}
/**
* \brief Read in the STEPWAT2 files and populate the grid. This only needs to be called once.
*
* Note that \ref gridCells must be allocated first.
*
* \sideeffect
* Many fields in the \ref gridCells array will be assigned values.
*
* \ingroup GRID_PRIVATE
*/
static void _init_stepwat_inputs(void)
{
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
}
/**
* \brief Reread input files.
*
* This is useful when transitioning from [spinup](\ref SPINUP)
* to the regular simulation. It is a quick way to reset everything
*
* Be careful because this function reallocates [the grid](\ref gridCells).
* Make sure you call \ref free_grid_memory before calling this function.
*
* \sideeffect
* The grid will be reallocated and all fields will be assigned the values
* from inputs.
*
* \ingroup GRID
*/
void rereadInputs(void){
_read_grid_setup();
_read_files();
_init_stepwat_inputs();
_init_grid_inputs();
}
/**
* \brief Allocates memory for the grid cells.
*
* This function only needs to be called once.
*
* \sideeffect
* \ref grid_Rows * \ref grid_Cols worth of [cells](\ref CellType)
* will be allocated.
*
* \ingroup GRID_PRIVATE
*/
static void _allocate_gridCells(int rows, int cols){
int i, j;
gridCells = (CellType**) Mem_Calloc(rows, sizeof(CellType*),
"_allocate_gridCells: rows", &LogInfo);
for(i = 0; i < rows; ++i){
gridCells[i] = (CellType*) Mem_Calloc(cols, sizeof(CellType),
"_allocate_gridCells: columns", &LogInfo);
}
/* 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.shouldSpinup = (int*)
Mem_Calloc(MAX_SPECIES, sizeof(int),
"_allocate_gridCells: mySpeciesInit", &LogInfo);
gridCells[i][j].someKillage = (Bool*) Mem_Calloc(1, sizeof(Bool),
"_allocate_gridCells: someKillage", &LogInfo);
// Allocate the cheatgrassPrecip variable for the Mortality module
setCheatgrassPrecip(0);
initCheatgrassPrecip();
gridCells[i][j].myCheatgrassPrecip = getCheatgrassPrecip();
// Allocate wildfireClimate for Mortality
setWildfireClimate(NULL);
initWildfireClimate();
gridCells[i][j].myWildfireClimate = getWildfireClimate();
}
}
}
/**
* \brief Initialize each gridCell's accumulators.
*
* Must be called after STEPWAT inputs have been read so the program knows
* which accumulators are necessary.
*
* \sideeffect
* Multiple [accumulators](\ref StatType) will be allocated to each
* [cell](\ref CellType). Of course, this means \ref gridCells must be
* allocated first.
*
* \ingroup GRID_PRIVATE
*/
static void _allocate_accumulators(void){
int i, j;
SppIndex sp;
GrpIndex rg;
/* 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].<accumulator> because the ST_stats accumulators are local. */
load_cell(i,j);
if (BmassFlags.graz) {
gridCells[i][j]._Grazed = (StatType*)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(StatType),
"allocate_accumulators(Grazed)", &LogInfo);
ForEachGroup(rg) {
gridCells[i][j]._Grazed[rg].s = (struct accumulators_st*)Mem_Calloc(SuperGlobals.runModelYears,
sizeof(struct accumulators_st), "_allocate_accumulators(Grazed)", &LogInfo);
}
}
if (BmassFlags.dist) {
gridCells[i][j]._Dist = (StatType*) Mem_Calloc(1, sizeof(StatType), "_allocate_accumulators(Dist)", &LogInfo);
gridCells[i][j]._Dist->s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Dist)", &LogInfo);
}
if (BmassFlags.ppt) {
gridCells[i][j]._Ppt = (StatType*) Mem_Calloc(1, sizeof(StatType), "_allocate_accumulators(PPT", &LogInfo);
gridCells[i][j]._Ppt->s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(PPT)", &LogInfo);
}
if (BmassFlags.tmp) {
gridCells[i][j]._Temp = (StatType*) Mem_Calloc(1, sizeof(StatType), "_allocate_accumulators(Temp)", &LogInfo);
gridCells[i][j]._Temp->s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Temp)", &LogInfo);
}
if (BmassFlags.grpb) {
gridCells[i][j]._Grp = (struct stat_st *)
Mem_Calloc( Globals->grpCount,
sizeof(struct stat_st),
"_allocate_accumulators(Grp)", &LogInfo);
ForEachGroup(rg){
gridCells[i][j]._Grp[rg].s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Grp[rg].s)", &LogInfo);
}
if (BmassFlags.size) {
gridCells[i][j]._Gsize = (struct stat_st *)
Mem_Calloc( Globals->grpCount,
sizeof(struct stat_st),
"_allocate_accumulators(GSize)", &LogInfo);
ForEachGroup(rg){
gridCells[i][j]._Gsize[rg].s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(GSize[rg].s)", &LogInfo);
}
}
if (BmassFlags.pr) {
gridCells[i][j]._Gpr = (struct stat_st *)
Mem_Calloc( Globals->grpCount,
sizeof(struct stat_st),
"_allocate_accumulators(Gpr)", &LogInfo);
ForEachGroup(rg){
gridCells[i][j]._Gpr[rg].s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Gpr[rg].s)", &LogInfo);
}
}
if (BmassFlags.wildfire || BmassFlags.prescribedfire) {
gridCells[i][j]._Gwf = (struct fire_st *)
Mem_Calloc( 1, sizeof(struct fire_st),
"_allocate_accumulators(Gwf)", &LogInfo);
gridCells[i][j]._Gwf->wildfire = (int *) Mem_Calloc( 1,
sizeof(int) * SuperGlobals.runModelYears,
"_allocate_accumulators(Gwf->wildfire)", &LogInfo);
gridCells[i][j]._Gwf->prescribedFire = (int **) Mem_Calloc( 1,
sizeof(int **) * SuperGlobals.max_rgroups,
"_allocate_accumulators(Gwf->prescribedfire", &LogInfo);
ForEachGroup(rg){
gridCells[i][j]._Gwf->prescribedFire[rg] = (int *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(int) * SuperGlobals.runModelYears,
"_allocate_accumulators(Gwf->prescribedFire)", &LogInfo);
}
}
}
if (MortFlags.group) {
gridCells[i][j]._Gestab = (struct stat_st *)
Mem_Calloc( Globals->grpCount,
sizeof(struct stat_st),
"_allocate_accumulators(Gestab)", &LogInfo);
gridCells[i][j]._Gmort = (struct stat_st *)
Mem_Calloc( Globals->grpCount,
sizeof(struct stat_st),
"_allocate_accumulators(Gmort)", &LogInfo);
ForEachGroup(rg){
gridCells[i][j]._Gestab[rg].s = (struct accumulators_st *)
Mem_Calloc( 1, sizeof(struct accumulators_st),
"_allocate_accumulators(Gestab[rg].s)", &LogInfo);
gridCells[i][j]._Gmort[rg].s = (struct accumulators_st *)
Mem_Calloc( GrpMaxAge(rg),
sizeof(struct accumulators_st),
"_allocate_accumulators(Gmort[rg].s)", &LogInfo);
}
}
if (BmassFlags.sppb) {
gridCells[i][j]._Spp = (struct stat_st *)
Mem_Calloc( Globals->sppCount,
sizeof(struct stat_st),
"_allocate_accumulators(Spp)", &LogInfo);
ForEachSpecies(sp){
gridCells[i][j]._Spp[sp].s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Spp[sp].s)", &LogInfo);
}
}
if (BmassFlags.indv) {
gridCells[i][j]._Indv = (struct stat_st*)
Mem_Calloc(Globals->sppCount,
sizeof(struct stat_st),
"_allocate_accumulators(Indv)", &LogInfo);
ForEachSpecies(sp) {
gridCells[i][j]._Indv[sp].s = (struct accumulators_st*)
Mem_Calloc(SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Indv[sp].s)", &LogInfo);
}
}
if (MortFlags.species) {
gridCells[i][j]._Sestab = (struct stat_st *)
Mem_Calloc( Globals->sppCount,
sizeof(struct stat_st),
"_allocate_accumulators(Sestab)", &LogInfo);
gridCells[i][j]._Smort = (struct stat_st *)
Mem_Calloc( Globals->sppCount,
sizeof(struct stat_st),
"_allocate_accumulators(Smort)", &LogInfo);
ForEachSpecies(sp){
gridCells[i][j]._Sestab[sp].s = (struct accumulators_st *)
Mem_Calloc( 1, sizeof(struct accumulators_st),
"_allocate_accumulators(Sestab[sp].s)", &LogInfo);
gridCells[i][j]._Smort[sp].s = (struct accumulators_st *)
Mem_Calloc( SppMaxAge(sp),
sizeof(struct accumulators_st),
"_allocate_accumulators(Smort[sp].s)", &LogInfo);
}
}
if (UseSeedDispersal) {
gridCells[i][j]._Sreceived = Mem_Calloc( Globals->sppCount, sizeof(struct stat_st),
"_allocate_accumulators(Sreceived)", &LogInfo);
ForEachSpecies(sp) {
gridCells[i][j]._Sreceived[sp].s = (struct accumulators_st *)
Mem_Calloc( SuperGlobals.runModelYears,
sizeof(struct accumulators_st),
"_allocate_accumulators(Sreceived[sp].s)",
&LogInfo);
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.
}
/**
* \brief Free all memory allocated to the gridded mode.
*
* This includes not only the [cells](\ref gridCells) but also the fields
* inside those cells.
*
* \sideeffect
* \ref gridCells will be completely deallocated.
*
* \ingroup GRID
*/
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)
int i, j;
/* 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);
#ifndef STDEBUG
deallocate_Globals(TRUE);
#endif
freeMortalityMemory();
free_all_sxw_memory();
stat_free_mem();
unload_cell();
free(gridCells[i][j].mySpeciesInit.shouldSpinup);
free(gridCells[i][j].someKillage);
free(gridCells[i][j].mySoils.depth);
free(gridCells[i][j].mySoils.evco);
free(gridCells[i][j].mySoils.gravel);
free(gridCells[i][j].mySoils.imperm);
free(gridCells[i][j].mySoils.matricd);
free(gridCells[i][j].mySoils.pclay);
free(gridCells[i][j].mySoils.psand);
free(gridCells[i][j].mySoils.soiltemp);
free(gridCells[i][j].mySoils.trco_forb);
free(gridCells[i][j].mySoils.trco_grass);
free(gridCells[i][j].mySoils.trco_shrub);
free(gridCells[i][j].mySoils.trco_tree);
}
}
for(i = 0; i < grid_Rows; ++i){
free(gridCells[i]);
}
free(gridCells);
}
/**
* \brief Load \ref gridCells[row][col] into the
* [global variables](\ref ST_globals.h).
*
* \param row the row in the \ref gridCells 2d array.
* \param col the column in the \ref gridCells 2d array.
*
* After calling this function all variables like \ref Species, \ref RGroup,
* and \ref Env will point to a specific cell. It will also pass along the
* cell-specific structs like \ref SXWResources to their specific modules.
*
* Any call to this function should have an accompanying call to