-
Notifications
You must be signed in to change notification settings - Fork 5
/
sxw.c
1252 lines (1066 loc) · 38.7 KB
/
sxw.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 sxw.c
* \brief Interface module for the STEPWAT2 to SOILWAT
* data flow.
*
* Application: STEPWAT2 - plant community dynamics simulator
* coupled with the SOILWAT2 model.
* History
* (9-May-2002) -- INITIAL CODING - cwb
* 28-Feb-02 - cwb - The model runs but plants die
* soon after establishment in a way that suggests
* chronic stretching of resources. At this time
* I'm setting the input to soilwat to be based on
* full-sized plants to provide maximum typical
* transpiration and interpreting that as "available"
* resource. Requires the addition of a new array to
* hold the summation of the maximum (mature) biomass
* of each group _Grp_BMass[]. The only affected routines
* in this file are SXW_Init() and SXW_Run_SOILWAT().
* But see also sxw_soilwat.c.
* 18-Jun-03 - cwb - Solved the basic problem above but
* we're still getting rapid increase in PR. Stepping
* through the code and comparing with the spreadsheet
* suggests rounding errors in the internal matrices that
* perform the decomposition of transpiration to per-group
* transpiration values, so I'm making those arrays
* double precision with the RealD typedef. This has
* the potential to cause bugs in dynamic memory
* routines, so pay attention to which arrays are
* 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)
* 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.
*
* \author CWB (initial coding)
* \author Chandler Haukap
* \date 9 May 2002 (initial coding)
* \ingroup SXW_PRIVATE
*/
/* =================================================== */
/* INCLUDES / DEFINES */
/* --------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sw_src/include/generic.h"
#include "sw_src/include/filefuncs.h"
#include "sw_src/include/myMemory.h"
#include "ST_steppe.h"
#include "ST_globals.h"
#include "sw_src/include/SW_Defines.h"
#include "sxw.h"
#include "sxw_funcs.h"
#include "sxw_module.h"
#include "sw_src/include/SW_Control.h"
#include "sw_src/include/SW_Model.h"
#include "sw_src/include/SW_VegProd.h"
#include "sw_src/include/SW_Carbon.h"
#include "sw_src/include/SW_Site.h"
#include "sw_src/include/SW_SoilWater.h"
#include "sw_src/include/SW_Files.h"
#include "sw_src/include/SW_Weather.h"
#include "sw_src/include/SW_Markov.h"
#include "sw_src/include/SW_Output.h"
#include "sw_src/include/rands.h"
#include "sw_src/include/Times.h"
#include "sw_src/include/SW_Domain.h"
/*************** Global Variable Declarations ***************/
/***********************************************************/
SXW_t* SXW;
SXW_resourceType* SXWResources;
sw_random_t resource_rng; //rng for swx_resource.c functions.
/*************** Module/Local Variable Declarations ***************/
/***********************************************************/
/* these are initialized and maybe populated here but are used
* in sxw_resource.c so they aren't declared static.
*/
// 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;
/* These are only used here so they are static. */
static char _swOutDefName[FILENAME_MAX];
static char *MyFileName;
static char **_sxwfiles[SXW_NFILES];
static char _debugout[256];
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);
static void _read_prod(void);
static void _read_watin(void);
static void _make_arrays(void);
static void _make_roots_arrays(void);
static void _make_phen_arrays(void);
static void _make_prod_arrays(void);
static void _make_transp_arrays(void);
static void _read_debugfile(void);
void _print_debuginfo(void);
void debugCleanUp(void);
static void _make_swc_array(void);
static void SXW_SW_Setup_Echo(void);
static void SXW_Reinit(char* SOILWAT_file, Bool zeroOutArrays);
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 );
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 ********************/
/**
* \brief Read [SOILWAT2](\ref sw_src) input files and initialize variables.
*
* \ingroup SXW
*/
void SXW_Init( Bool init_SW, char *f_roots ) {
/* read SOILWAT2's input files and initialize some variables */
/* The shorthand table dimensions are set at the point
* at which they become defined in _read_files().
*
* 2/14/03 - cwb - Added the summation for each group's biomass
* as per the notes at the top of the file.
*
* 2/21/15 - rjm - new param f_roots is a replacement for the regular
* roots file. This is for the gridded version where soils needs to
* match sxwroots.in
*/
char roots[MAX_FILENAMESIZE] = { '\0' };
// FIXME: seed with appropriate iter, year, and cell_id
// RNG ID 7, see `set_all_rngs()`
RandSeed(SuperGlobals.randseed, RNG_INITSEQ(7, 0, 0, 0), &resource_rng);
_allocate_memory(); //Allocate memory for all local pointers
_sxwfiles[0] = &SXW->f_roots;
_sxwfiles[1] = &SXW->f_phen;
_sxwfiles[2] = &SXW->f_prod;
_sxwfiles[3] = &SXW->f_watin;
SXW->debugfile = NULL;
SXW->NGrps = Globals->grpCount;
_read_files();
if(f_roots != NULL) {
//Copy the directory for the sxwroots files
DirName(*_sxwfiles[0], roots);
strcat(roots, f_roots);
free(*_sxwfiles[0]);
_sxwfiles[0] = &SXW->f_roots;
*_sxwfiles[0] = Str_Dup(roots, &LogInfo);
}
SXW->NPds = MAX_MONTHS;
_read_watin();
if (SXW->debugfile)
_read_debugfile();
if (init_SW)
{
// we need to deallocate memory previously dynamically allocated
// by SOILWAT2 in global variables, e.g., `SoilWatRun`,
// as long as these variables are reused/shared,
// e.g., among grid cells or among iterations
SXW_Reset(SXW->f_watin, TRUE);
}
SXW->NTrLyrs = SoilWatRun.Site.n_transp_lyrs[0];
if(SoilWatRun.Site.n_transp_lyrs[1] > SXW->NTrLyrs)
SXW->NTrLyrs = SoilWatRun.Site.n_transp_lyrs[1];
if(SoilWatRun.Site.n_transp_lyrs[3] > SXW->NTrLyrs)
SXW->NTrLyrs = SoilWatRun.Site.n_transp_lyrs[3];
if(SoilWatRun.Site.n_transp_lyrs[2] > SXW->NTrLyrs)
SXW->NTrLyrs = SoilWatRun.Site.n_transp_lyrs[2];
SXW->NSoLyrs = SoilWatRun.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();
_read_roots_max();
_read_phen();
_read_prod();
_sxw_root_phen();
#ifdef TESTING
_sxw_test();
exit(0);
#endif
}
/**
* @brief This function initializes and allocates SOILWAT2 structures,
* and reads SOILWAT2 inputs.
*
* @note De-allocate dynamically allocated memory in SOILWAT2 structures
* if it has been previously allocated before SXW_Reinit() is called,
* e.g., use SXW_Reset() instead.
*
* \ingroup SXW
*/
static void SXW_Reinit(char* SOILWAT_file, Bool zeroOutArrays) {
SoilWatDomain.PathInfo.InFiles[eFirst] = Str_Dup(SOILWAT_file, &LogInfo);
SW_CTL_setup_domain(0, &SoilWatDomain, &LogInfo);
// Update output domain with STEPWAT2's version of
// prepare_IterationSummary and storeAllIterations
SoilWatDomain.OutDom.prepare_IterationSummary = SuperGlobals.prepare_IterationSummary;
SoilWatDomain.OutDom.print_SW_Output = SuperGlobals.storeAllIterations;
SoilWatDomain.OutDom.storeAllIterations = SuperGlobals.storeAllIterations;
SW_CTL_setup_model(&SoilWatRun, &SoilWatDomain.OutDom, zeroOutArrays, &LogInfo);
SW_MDL_get_ModelRun(&SoilWatRun.Model, &SoilWatDomain, NULL, &LogInfo);
// read user inputs
SoilWatRun.Model.runModelIterations = SuperGlobals.runModelIterations;
SoilWatRun.Model.runModelYears = SuperGlobals.runModelYears;
SW_CTL_read_inputs_from_disk(&SoilWatRun, &SoilWatDomain.OutDom,
&SoilWatDomain.PathInfo, &LogInfo);
// initialize simulation run (based on user inputs)
SW_CTL_init_run(&SoilWatRun, &LogInfo);
SW_DOM_soilProfile(
&SoilWatDomain.hasConsistentSoilLayerDepths,
&SoilWatDomain.nMaxSoilLayers,
&SoilWatDomain.nMaxEvapLayers,
SoilWatDomain.depthsAllSoilLayers,
SoilWatRun.Site.n_layers,
SoilWatRun.Site.n_evap_lyrs,
SoilWatRun.Site.depths,
&LogInfo
);
SW_OUT_setup_output(
SoilWatDomain.nMaxSoilLayers,
SoilWatDomain.nMaxEvapLayers,
&SoilWatRun.VegEstab,
&SoilWatDomain.OutDom,
&LogInfo
);
// initialize output: transfer between STEPPE and SOILWAT2
SW_OUT_set_SXWrequests(&SoilWatDomain.OutDom, &LogInfo);
SW_CTL_alloc_outptrs(&SoilWatRun, &LogInfo);
}
/**
* @brief This function resets the model to default conditions
*
* It clears SOILWAT2-memory, initializes and allocates SOILWAT2 structures,
* and reads SOIILWAT2 inputs.
*
* However, it does **not** reset memory allocated by
* `SW_OUT_construct_outarray` because those variables are carrying
* 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()`).
*
* \ingroup SXW
*/
void SXW_Reset(char* SOILWAT_file, Bool zeroOutArrays) {
SW_DOM_deconstruct(&SoilWatDomain);
SW_CTL_clear_model(FALSE, &SoilWatRun); // don't reset output arrays
SXW_Reinit(SOILWAT_file, zeroOutArrays);
}
/**
* \brief Resets the SOILWAT2 transpiration tables. This should be called
* every iteration.
*
* \sa Plot_Init() where this function is called.
*
* \ingroup SXW
*/
void SXW_InitPlot (void) {
_sxw_sw_clear_transp();
_sxw_update_resource();
}
/**
* \brief Executes SOILWAT2 which generates soil water resources for plants to
* utilize this year.
*
* \sa Env_Generate() where this function is called.
*
* \ingroup SXW
*/
void SXW_Run_SOILWAT(void) {
GrpIndex g;
Int j;
SppIndex sp;
RealF *sizes;
sizes = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups,
sizeof(RealF), "SXW_Run_SOILWAT", &LogInfo);
/* 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) {
sizes[g] = RGroup_GetBiomass(g);
//printf("First call to sizes: RGroup = %s, sizes[g] = %f\n", RGroup[g]->name, sizes[g]);
ForEachEstSpp(sp, g, j) {
/* For annual species, increment the biomass that is passed into SOILWAT2 to also include last year's biomass, in addition to biomass due to establishment this year */
if (Species[sp]->max_age == 1) {
sizes[g] += Species[sp]->lastyear_relsize * Species[sp]->mature_biomass;
}
}
//printf("Second call to sizes: RGroup = %s, sizes[g] = %f\n", RGroup[g]->name, sizes[g]);
}
_sxw_sw_setup(sizes);
// Generate weather for current call (iteration, year, cell, ...)
_sxw_generate_weather();
// Initialize `SXW` values for current year's run:
SXW->aet = 0.; /* used to be in sw_setup() but it needs clearing each run */
//SXW_SW_Setup_Echo();
_sxw_sw_run();
/* Now compute resource availability for each STEPPE functional group */
_sxw_update_resource();
/* Set annual precipitation and annual temperature */
_sxw_set_environs();
free(sizes);
}
void SXW_SW_Setup_Echo(void) {
char name[256] = {0};
strcat(name, _debugout);
FILE *f = OpenFile(strcat(name, ".input.out"), "a", &LogInfo);
int i;
fprintf(f, "\n================== %d ==============================\n", SoilWatRun.Model.year);
fprintf(f,"Fractions Grass:%f Shrub:%f Tree:%f Forb:%f BareGround:%f\n", SoilWatRun.VegProd.veg[3].cov.fCover,
SoilWatRun.VegProd.veg[1].cov.fCover, SoilWatRun.VegProd.veg[0].cov.fCover, SoilWatRun.VegProd.veg[2].cov.fCover,
SoilWatRun.VegProd.bare_cov.fCover);
fprintf(f,"Monthly Production Values\n");
fprintf(f,"Grass\n");
fprintf(f,"Month\tLitter\tBiomass\tPLive\tLAI_conv\n");
for (i = 0; i < 12; i++) {
fprintf(f,"%u\t%f\t%f\t%f\t%f\n", i + 1, SoilWatRun.VegProd.veg[3].litter[i],
SoilWatRun.VegProd.veg[3].biomass[i], SoilWatRun.VegProd.veg[3].pct_live[i],
SoilWatRun.VegProd.veg[3].lai_conv[i]);
}
fprintf(f,"Shrub\n");
fprintf(f,"Month\tLitter\tBiomass\tPLive\tLAI_conv\n");
for (i = 0; i < 12; i++) {
fprintf(f,"%u\t%f\t%f\t%f\t%f\n", i + 1, SoilWatRun.VegProd.veg[1].litter[i],
SoilWatRun.VegProd.veg[1].biomass[i], SoilWatRun.VegProd.veg[1].pct_live[i],
SoilWatRun.VegProd.veg[1].lai_conv[i]);
}
fprintf(f,"Tree\n");
fprintf(f,"Month\tLitter\tBiomass\tPLive\tLAI_conv\n");
for (i = 0; i < 12; i++) {
fprintf(f,"%u\t%f\t%f\t%f\t%f\n", i + 1, SoilWatRun.VegProd.veg[0].litter[i],
SoilWatRun.VegProd.veg[0].biomass[i], SoilWatRun.VegProd.veg[0].pct_live[i],
SoilWatRun.VegProd.veg[0].lai_conv[i]);
}
fprintf(f,"Forb\n");
fprintf(f,"Month\tLitter\tBiomass\tPLive\tLAI_conv\n");
for (i = 0; i < 12; i++) {
fprintf(f,"%u\t%f\t%f\t%f\t%f\n", i + 1, SoilWatRun.VegProd.veg[2].litter[i],
SoilWatRun.VegProd.veg[2].biomass[i], SoilWatRun.VegProd.veg[2].pct_live[i],
SoilWatRun.VegProd.veg[2].lai_conv[i]);
}
SW_SITE *s = &SoilWatRun.Site;
fprintf(f,"Soils Transp_coeff\n");
fprintf(f,"Forb\tTree\tShrub\tGrass\n");
ForEachSoilLayer(i, s->n_layers)
{// %u %u %u %u s->lyr[i]->my_transp_rgn_forb, s->lyr[i]->my_transp_rgn_tree, s->lyr[i]->my_transp_rgn_shrub, s->lyr[i]->my_transp_rgn_grass
fprintf(f,"%6.2f %6.2f %6.2f %6.2f\n", s->transp_coeff[2][i],
s->transp_coeff[0][i], s->transp_coeff[1][i], s->transp_coeff[3][i]);
}
// 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;*/
fprintf(f, "\n");
CloseFile(&f, &LogInfo);
}
/**
* \brief Obtain transpiration (resource availability) for each resource group.
*
* \param rg is the [index](\ref GrpIndex) in \ref RGroup of the resource group.
*
* \return The transpiration availible for \ref RGroup[rg].
*/
RealF SXW_GetTranspiration( GrpIndex rg) {
return SXWResources->_resource_cur[rg];
}
void SXW_PrintDebug(Bool cleanup) {
/*======================================================*/
TimeInt i;
static Bool beenhere = FALSE;
if(cleanup) {
debugCleanUp();
} else {
for (i = 0; i < _debugyrs_cnt; i++) {
if (SoilWatRun.Model.year == _debugyrs[i]) {
SXW_SW_Setup_Echo();
_print_debuginfo();
break;
}
}
if (!beenhere) {
beenhere = TRUE;
insertInfo();
insertSXWPhen();
insertSXWProd();
insertRootsXphen(SXWResources->_rootsXphen);
}
insertInputVars();
insertInputProd();
insertInputSoils();
insertOutputVars(SXWResources->_resource_cur, transp_window->added_transp);
insertRgroupInfo(SXWResources->_resource_cur);
insertOutputProd(&SoilWatRun.VegProd);
insertRootsSum(SXWResources->_roots_active_sum);
insertRootsRelative(SXWResources->_roots_active_rel);
insertTranspiration();
insertSWCBulk();
}
}
/** \brief Allocate memory for sxw local variables.
*
* Local variables allocated are SXW, transp_window, and SXWResources.
* However, memory allocation in SXW is not modularized well. Check
* \ref _make_arrays(), \ref _make_roots_arrays(),
* \ref _make_phen_arrays(), \ref _make_prod_arrays(),
* \ref _make_transp_arrays(), and \ref _make_swc_array() before assuming that
* something isn't allocated.
*
* \ingroup SXW_private
*/
static void _allocate_memory(void){
transp_window = (transp_t*) Mem_Calloc(1, sizeof(transp_t), "_allocate_memory: transp_window", &LogInfo);
/* Set the size of our transpiration window. */
if(Globals->transp_window > MAX_WINDOW){
LogError(&LogInfo, 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", &LogInfo);
transp_window->transp = (RealF*) Mem_Calloc(transp_window->size, sizeof(RealF),
"_allocate_memory: transp_window->transp", &LogInfo);
transp_window->SoS_array = (RealF*) Mem_Calloc(transp_window->size, sizeof(RealF),
"_allocate_memory: transp_window->SoS_array", &LogInfo);
SXW = (SXW_t*) Mem_Calloc(1, sizeof(SXW_t), "_allocate_memory: SXW", &LogInfo);
SXWResources = (SXW_resourceType*) Mem_Calloc(1, sizeof(SXW_resourceType),
"_allocate_memory: SXWResources", &LogInfo);
SXWResources->_resource_cur = (RealF *)Mem_Calloc(SuperGlobals.max_rgroups, sizeof(RealF),
"_allocate_memory: _resource_cur", &LogInfo);
}
/* 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 ) {
/*======================================================*/
/* read list of input files. */
FILE *fin;
int i, nfiles = SXW_NFILES;
char inbuf[MAX_FILENAMESIZE];
SXW->f_files = Parm_name(F_SXW); /* aliased */
MyFileName = SXW->f_files;
fin = OpenFile(MyFileName,"r", &LogInfo);
for(i=0; i < nfiles; i++) {
if (!GetALine(fin, inbuf, MAX_FILENAMESIZE)) break;
*_sxwfiles[i] = Str_Dup(Str_TrimLeftQ(inbuf), &LogInfo);
}
if (i < nfiles) {
LogError(&LogInfo, LOGERROR, "STEPWAT: %s: Insufficient files found",
MyFileName);
}
CloseFile(&fin, &LogInfo);
}
static void _read_roots_max(void) {
/*======================================================*/
GrpIndex g;
int cnt = 0, lyr;
char *p;
char *name;
FILE *fp;
char inbuf[MAX_FILENAMESIZE];
name = (char *)Mem_Calloc(SuperGlobals.max_groupnamelen + 1, sizeof(char), "_read_roots_max", &LogInfo);
MyFileName = SXW->f_roots;
fp = OpenFile(MyFileName, "r", &LogInfo);
while (GetALine(fp, inbuf, MAX_FILENAMESIZE)) {
p = strtok(inbuf, " \t"); /* g'teed to work via GetALine() */
if ((g = RGroup_Name2Index(p)) < 0) {
LogError(&LogInfo, LOGERROR, "%s: Invalid group name (%s) found.",
MyFileName, p);
}
strcpy(name, p);
cnt++;
lyr = 0;
while ((p = strtok(NULL, " \t"))) {
SXWResources->_roots_max[Ilg(lyr, g)] = atof(p);
lyr++;
}
if (lyr != SXW->NTrLyrs) {
LogError(&LogInfo, LOGERROR,
"%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);
}
}
if (cnt < Globals->grpCount) {
LogError(&LogInfo, LOGERROR, "%s: Not enough valid groups found.",
MyFileName);
}
CloseFile(&fp, &LogInfo);
free(name);
}
static void _read_phen(void) {
/*======================================================*/
GrpIndex g;
IntUS cnt=0;
TimeInt m;
char *p;
FILE *fp;
char inbuf[MAX_FILENAMESIZE];
MyFileName = SXW->f_phen;
fp = OpenFile(MyFileName,"r", &LogInfo);
while( GetALine(fp, inbuf, MAX_FILENAMESIZE) ) {
p = strtok(inbuf," \t"); /* g'teed to work via GetALine() */
if ( (g=RGroup_Name2Index(p)) <0 ) {
LogError(&LogInfo, LOGERROR,
"%s: Invalid group name (%s) found.", MyFileName, p);
}
cnt++;
m = Jan;
while ((p=strtok(NULL," \t")) ) {
if (m > Dec) {
LogError(&LogInfo, LOGERROR,
"%s: More than 12 months of data found.", MyFileName);
}
SXWResources->_phen[Igp(g,m)] = atof(p);
m++;
}
}
if (cnt < Globals->grpCount) {
LogError(&LogInfo, LOGERROR,
"%s: Not enough valid groups found.", MyFileName);
}
CloseFile(&fp, &LogInfo);
}
/** \brief Read the values from the SXW prod file.
*
* These values are LITTER, BIOMASS, and PCTLIVE. All three values are input
* for each group for each month in separate two dimensional tables. If a table
* if poorly formated, i.e. incorrect \ref RGroup names, incorrect number of
* months, or incorrect number of \ref RGroups, this function will throw a
* fatal error.
*
* \sideeffect
* Populates multiple one dimensional and two dimensional arrays.
*
* \ingroup SXW_private
*/
static void _read_prod(void) {
FILE *fp;
TimeInt month = Jan;
GrpIndex g;
IntUS count = 0;
char *p;
char * pch;
char inbuf[MAX_FILENAMESIZE];
MyFileName = SXW->f_prod;
fp = OpenFile(MyFileName, "r", &LogInfo);
/* Read LITTER values for each group for each month */
while (GetALine(fp, inbuf, MAX_FILENAMESIZE)) {
pch = strstr(inbuf, "[end]");
if(pch != NULL) break;
p = strtok(inbuf, " \t"); /* guaranteed to work via GetALine() */
if ((g = RGroup_Name2Index(p)) < 0) {
LogError(&LogInfo, LOGERROR, "%s: Invalid group name for LITTER (%s).",
MyFileName, p);
}
month = Jan;
while ((p = strtok(NULL, " \t"))) {
if (month > Dec) {
LogError(&LogInfo, LOGERROR,
"%s: More than 12 months of data found for LITTER.", MyFileName);
}
SXWResources->_prod_litter[g][month] = atof(p);
month++;
}
count++;
if(count == SXW->NGrps)
break;
}
if (count < Globals->grpCount) {
LogError(&LogInfo, LOGERROR, "%s: Not enough valid groups found for LITTER values.",
MyFileName);
}
/* Read BIOMASS values for each group for each month */
GetALine(fp,inbuf, MAX_FILENAMESIZE); /* toss [end] keyword */
month = Jan;
count = 0;
while (GetALine(fp, inbuf, MAX_FILENAMESIZE)) {
pch = strstr(inbuf, "[end]");
if(pch != NULL)
break;
p = strtok(inbuf, " \t"); /* guaranteed to work via GetALine() */
if ((g = RGroup_Name2Index(p)) < 0) {
LogError(&LogInfo, LOGERROR, "%s: Invalid group name for biomass (%s) found.",
MyFileName, p);
}
month = Jan;
while ((p = strtok(NULL, " \t"))) {
if (month > Dec) {
LogError(&LogInfo, LOGERROR,
"%s: More than 12 months of data found.", MyFileName);
}
SXWResources->_prod_bmass[Igp(g, month)] = atof(p);
month++;
}
count++;
if(count == SXW->NGrps)
break;
}
if (count < Globals->grpCount) {
LogError(&LogInfo, LOGERROR, "%s: Not enough valid groups found.",
MyFileName);
}
/* Read PCTLIVE values for each group for each month */
GetALine(fp, inbuf, MAX_FILENAMESIZE); /* toss [end] keyword */
month = Jan;
count=0;
while (GetALine(fp, inbuf, MAX_FILENAMESIZE)) {
pch = strstr(inbuf, "[end]");
if (pch != NULL)
break;
p = strtok(inbuf, " \t"); /* guaranteed to work via GetALine() */
if ((g = RGroup_Name2Index(p)) < 0) {
LogError(&LogInfo, LOGERROR,
"%s: Invalid group name for pctlive (%s) found.",
MyFileName, p);
}
month = Jan;
while ((p = strtok(NULL, " \t"))) {
if (month > Dec) {
LogError(&LogInfo, LOGERROR,
"%s: More than 12 months of data found.", MyFileName);
}
SXWResources->_prod_pctlive[Igp(g, month)] = atof(p);
month++;
}
count++;
if (count == SXW->NGrps)
break;
}
if (count < Globals->grpCount) {
LogError(&LogInfo, LOGERROR, "%s: Not enough valid groups found.",
MyFileName);
}
GetALine(fp, inbuf, MAX_FILENAMESIZE); /* toss [end] keyword */
CloseFile(&fp, &LogInfo);
}
static void _read_watin(void) {
/*======================================================*/
/* get the name of the soilwat output definition file. */
/* assume that there is no path prepended to the file
* specification in the SOILWAT input files. It might be
* nice to allow relative paths, but there's really no need
* for it as far as the STEPWAT program is concerned because
* all the SOILWAT input files should be in one directory
* and that is defined in sxw.in. Thus, we'll treat the
* outsetup.in filename as though it has no dirname and
* append it to the soilwat input dirname.
*/
FILE *f;
int lineno = 0;
Bool found = FALSE;
char inbuf[MAX_FILENAMESIZE], outString[MAX_FILENAMESIZE];
MyFileName = SXW->f_watin;
f = OpenFile(MyFileName, "r", &LogInfo);
while( GetALine(f, inbuf, MAX_FILENAMESIZE) ) {
if (++lineno == (eOutput + 2)) {
DirName(SXW->f_watin, outString);
strcpy(_swOutDefName, outString);
strcat(_swOutDefName, inbuf);
found = TRUE;
break;
}
}
CloseFile(&f, &LogInfo);
if (!found) {
LogError(&LogInfo, LOGERROR,
"%s: Too few files (%d)", MyFileName, lineno);
}
}
static void _make_arrays(void) {
/*======================================================*/
/* central point to make all dynamically allocated arrays
* now that the dimensions are known.
*/
_make_roots_arrays();
_make_phen_arrays();
_make_prod_arrays();
_make_transp_arrays();
_make_swc_array();
}
static void _make_roots_arrays(void) {
/*======================================================*/
int size;
char *fstr = "_make_roots_array()";
size = SXW->NGrps * SXW->NTrLyrs;
SXWResources->_roots_max = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
size = SXW->NGrps * SXW->NPds * SXW->NTrLyrs;
SXWResources->_rootsXphen = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
SXWResources->_roots_active = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
SXWResources->_roots_active_rel = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
//4 - Grass,Frob,Tree,Shrub
size = NVEGTYPES * SXW->NPds * SXW->NTrLyrs;
SXWResources->_roots_active_sum = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
}
static void _make_phen_arrays(void) {
/*======================================================*/
int size;
char *fstr = "_make_phen_arrays()";
size = SXW->NGrps * MAX_MONTHS;
SXWResources->_phen = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
}
/** \brief Allocate the "prod" arrays.
*
* _prod_bmass, _prod_pctlive, and _prod_litter from the \ref SXWResources
* struct are all allocated here.
*
* \sideeffect two arrays and one 2D array will be allocated.
*
* \ingroup
*/
static void _make_prod_arrays(void) {
int size, i;
char *fstr = "_make_phen_arrays()";
size = SXW->NGrps * MAX_MONTHS;
SXWResources->_prod_bmass = (RealD *) Mem_Calloc(size, sizeof(RealD),
fstr, &LogInfo);
SXWResources->_prod_pctlive = (RealD *) Mem_Calloc(size, sizeof(RealD),
fstr, &LogInfo);
/* Allocate the _prod_litter 2D array, where rows are rgroups and columns are months. */
SXWResources->_prod_litter = (RealD**) Mem_Calloc(SXW->NGrps, sizeof(RealD*), fstr, &LogInfo);
for(i = 0; i < SXW->NGrps; ++i){
SXWResources->_prod_litter[i] = (RealD*) Mem_Calloc(MAX_MONTHS, sizeof(RealD), fstr, &LogInfo);
}
}
static void _make_transp_arrays(void) {
/*======================================================*/
/* 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, &LogInfo);
ForEachVegType(k) {
SXW->transpVeg[k] = (RealD *) Mem_Calloc(size, sizeof(RealD), fstr, &LogInfo);
}
}
static void _make_swc_array(void) {
/*======================================================*/
/* 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
SXW->swc = (RealF *) Mem_Calloc(size, sizeof(RealF *), fstr, &LogInfo);
}
static void _read_debugfile(void) {
/*======================================================*/
/* provides a way to specify optional debug information
* to be printed at various points in the model run.
*
* 7-Jan-03 - format of file is as follows:
* debugfilename #name of file to write debuginfo to (len<256 chars)
* yyyy yyyy yyyy ... # 4-digit years to write output (see years.in)
* yyyy yyyy yyyy ... # possible multi-line continuation of above
*
* Notes:
* - LIMIT of 100 4-digit years
*
* - You'll probably want to limit the number of model iterations to 1.
*
* - Start year is defined in SOILWAT's model parameter file
* (probably years.in).
*
* -If you want to add more sections, use something like [end] after
* each and test to break out of the current section's loop. Eg,
* while (GetALine(f,inbuf) && !strcmp(inbuf, "[end]") ) {...}
* with the above example, don't forget to test for end of file (EOF)
* before continuing.
*/
FILE *f;
char *date, str[102];
int cnt = 0;
TimeInt i;
char name[256] = {0}, inbuf[MAX_FILENAMESIZE], errstr[MAX_ERROR];
f = OpenFile(SXW->debugfile, "r", &LogInfo);
/* get name of output file */
if (!GetALine(f, inbuf, MAX_FILENAMESIZE)) {
CloseFile(&f, &LogInfo);
return;
}
strcpy(_debugout, inbuf);
/* get output years */
while (GetALine(f, inbuf, MAX_FILENAMESIZE)) {
_debugyrs[cnt++] = atoi(strtok(inbuf, " \t")); /* g'teed via getaline() */
while (NULL != (date = strtok(NULL, " \t"))) {
_debugyrs[cnt++] = atoi(date);
}
}
_debugyrs_cnt = cnt;
sprintf(errstr, "Debugging Transpiration turned on.\n%s will contain"
" %d years of output:\n", _debugout, _debugyrs_cnt);
for (i = 0; i < _debugyrs_cnt; i++) {
sprintf(str, "%d\n", _debugyrs[i]);
strcat(errstr, str);
}
strcat(errstr, "Note that data will always be appended,\n");
strcat(errstr, "so clear file contents before re-use.\n");
LogError(&LogInfo, LOGWARN, errstr);
CloseFile(&f, &LogInfo);
/* now empty the file prior to the run */
strcat(name, _debugout);
f = OpenFile(strcat(name, ".output.out"), "w", &LogInfo);
CloseFile(&f, &LogInfo);
name[0] = 0;
strcat(name, _debugout);
f = OpenFile(strcat(name, ".input.out"), "w", &LogInfo);
CloseFile(&f, &LogInfo);
connect(_debugout);
createTables();
}
void debugCleanUp() {
printf("in debugCleanUp\n");
disconnect();
}
void _print_debuginfo(void) {
/*======================================================*/
SW_VEGPROD *v = &SoilWatRun.VegProd;
TimeInt p;
LyrIndex t;
int l;
FILE *f;
GrpIndex r;
RealF sum = 0.;