diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 000000000..de8dc2a83 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,34 @@ +--- +# Checks + accepted suppressions for SOILWAT2 +Checks: > + clang-diagnostic-*, + clang-analyzer-*, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + bugprone-*, + -bugprone-easily-swappable-parameters, + cert-*, + concurrency-*, + -concurrency-mt-unsafe, + cppcoreguidelines-*, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-to-enum, + misc-*, + -misc-include-cleaner, + mpi-*, + performance-*, + portability-*, + readability-*, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-magic-numbers +WarningsAsErrors: '*' +HeaderFilterRegex: '' +FormatStyle: none +SystemHeaders: false +CheckOptions: + - key: readability-braces-around-statements.ShortStatementLines + value: '2' + - key: readability-uppercase-literal-suffix.NewSuffixes + value: 'L;LL;LU;LLU' +... diff --git a/.clang-tidy_swtest b/.clang-tidy_swtest new file mode 100644 index 000000000..fb462477b --- /dev/null +++ b/.clang-tidy_swtest @@ -0,0 +1,43 @@ +--- +# Checks + accepted suppressions for SOILWAT2 tests +Checks: > + clang-diagnostic-*, + clang-analyzer-*, + -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, + bugprone-*, + -bugprone-easily-swappable-parameters, + cert-*, + concurrency-*, + -concurrency-mt-unsafe, + cppcoreguidelines-*, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-goto, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-init-variables, + -cppcoreguidelines-macro-to-enum, + -cppcoreguidelines-no-malloc, + -cppcoreguidelines-owning-memory, + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, + -cppcoreguidelines-pro-bounds-constant-array-index, + -cppcoreguidelines-pro-bounds-pointer-arithmetic, + -cppcoreguidelines-pro-type-cstyle-cast, + -cppcoreguidelines-pro-type-vararg, + misc-*, + -misc-include-cleaner, + mpi-*, + performance-*, + portability-*, + readability-*, + -readability-function-cognitive-complexity, + -readability-identifier-length, + -readability-magic-numbers +WarningsAsErrors: '*' +HeaderFilterRegex: '' +FormatStyle: none +SystemHeaders: false +CheckOptions: + - key: readability-braces-around-statements.ShortStatementLines + value: '2' + - key: readability-uppercase-literal-suffix.NewSuffixes + value: 'L;LL;LU;LLU' +... diff --git a/.github/workflows/clang-tidy-check.yml b/.github/workflows/clang-tidy-check.yml new file mode 100644 index 000000000..ac2135b0a --- /dev/null +++ b/.github/workflows/clang-tidy-check.yml @@ -0,0 +1,29 @@ +name: clang-tidy check + +# ubuntu-24.04 comes with clang v18 as default +# ubuntu-latest as of 2024-Aug-01 points to ubuntu-22.04 with clang v14 + +on: + push: + branches: [master, main, release/**] + pull_request: + branches: [master, main, release/**] + +jobs: + formatting-check: + name: Tidy Check + runs-on: ubuntu-24.04 + + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install netCDF-C and udunits2 + run: | + sudo apt-get update + sudo apt-get install libnetcdf-dev libudunits2-dev + + - name: Run + run: ./tools/run_tidy.sh diff --git a/doc/additional_pages/code_contribution_guidelines.md b/doc/additional_pages/code_contribution_guidelines.md index 26e0885ae..59d60b45b 100644 --- a/doc/additional_pages/code_contribution_guidelines.md +++ b/doc/additional_pages/code_contribution_guidelines.md @@ -12,6 +12,7 @@ [netCDF]: https://downloads.unidata.ucar.edu/netcdf/ [udunits2]: https://downloads.unidata.ucar.edu/udunits/ [ClangFormat]: https://clang.llvm.org/docs/ClangFormat.html +[clang-tidy]: https://clang.llvm.org/extra/clang-tidy [iwyu]:https://include-what-you-use.org/ @@ -21,8 +22,9 @@ Go back to the [main page](README.md). 1. [SOILWAT2 code](#SOILWAT2_code) 2. [Code guidelines](#guidelines) 1. [Code format](#code_format) - 2. [Include directives](#includes) - 3. [Other guidelines](#other_guidelines) + 2. [Code checks](#code_checks) + 3. [Include directives](#includes) + 4. [Other guidelines](#other_guidelines) 3. [Code documentation](#code_documentation) 4. [Code tests](#code_tests) 1. [Unit tests](#unit_tests) @@ -135,6 +137,27 @@ checks code style for pull requests into the main branch and release branches.
+ + +### Code checks + +We use [clang-tidy][] to check code in the `SOILWAT2` repository. + +The files `".clang-tidy"` and `".clang-tidy_swtests"` document all details +related to these code checks. + +We have `make` targets `"tidy-bin"` and `"tidy-test"` to run these checks on +the code and on the test code respectively. + +We also have a script `"tools/run_tidy.sh"` that runs all appropriate checks. +The script exits with a failure code if any check reports code issues. + +A github action workflow `".github/workflows/clang-tidy-check.yml"` +checks code for pull requests into the main branch and release branches. + +
+ + ### Include directives diff --git a/include/SW_Control.h b/include/SW_Control.h index d87ae805b..015cd9557 100644 --- a/include/SW_Control.h +++ b/include/SW_Control.h @@ -33,7 +33,7 @@ void SW_CTL_init_ptrs(SW_RUN *sw); void SW_CTL_alloc_outptrs(SW_RUN *sw, LOG_INFO *LogInfo); void SW_RUN_deepCopy( - SW_RUN *source, SW_RUN *dest, SW_OUT_DOM *DomRun, LOG_INFO *LogInfo + SW_RUN *source, SW_RUN *dest, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo ); void SW_CTL_setup_domain( diff --git a/include/SW_Defines.h b/include/SW_Defines.h index 10ed404e1..698ae9dae 100644 --- a/include/SW_Defines.h +++ b/include/SW_Defines.h @@ -22,8 +22,7 @@ #ifndef SOILW_DEF_H #define SOILW_DEF_H -#include "include/generic.h" // for IntUS, RealF -#include // for time_t, timespec +#include // for time_t, timespec #if !defined(RSOILWAT) /* rSOILWAT2 uses R's RNGs */ #include "external/pcg/pcg_basic.h" // for pcg32_random_t @@ -119,7 +118,7 @@ extern "C" { #define OUT_DIGITS 6 /** Separator used when generating text-based output files (csv-format) */ -#define _OUTSEP ',' +#define OUTSEP ',' // was 256 & 1024... #define MAX_FILENAMESIZE 512 @@ -171,9 +170,8 @@ extern "C" { #define MAX_WEEKS 53 #define MAX_DAYS 366 -#define SWRC_PARAM_NMAX \ - 6 /**< Maximal number of SWRC parameters implemented \ - */ +/** Maximal number of SWRC parameters implemented */ +#define SWRC_PARAM_NMAX 6 /* Indices to daily input flags/indices (dailyInputFlags & dailyInputIndices in @@ -217,8 +215,8 @@ extern "C" { #define eSW_Year 3 #define eSW_NoTime 999 // no time period // c++ doesn't support (pd)++ for pd as a typedef enum OutPeriod in -// macro `ForEachOutPeriod` --> instead, define as type `IntUS` -typedef IntUS OutPeriod; +// macro `ForEachOutPeriod` --> instead, define as type unsigned int +typedef unsigned short OutPeriod; /* * Number of output keys @@ -281,7 +279,7 @@ typedef IntUS OutPeriod; * before I got the documentation. */ typedef struct { - RealF xinflec, yinflec, range, slope; + double xinflec, yinflec, range, slope; } tanfunc_t; /* standardize the test for missing */ @@ -317,6 +315,14 @@ typedef struct timespec WallTimeSpec; typedef time_t WallTimeSpec; #endif +/* Memory copying via `sw_memccpy()` and SOILWAT2's custom function */ +#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L) || \ + (defined(__STDC__) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 202311L) +#define sw_memccpy memccpy +#else +#define sw_memccpy sw_memccpy_custom +#endif /* =================================================== */ /* RNG structs */ diff --git a/include/SW_Files.h b/include/SW_Files.h index 128c8947d..dac0add19 100644 --- a/include/SW_Files.h +++ b/include/SW_Files.h @@ -78,7 +78,9 @@ void SW_F_deepCopy(PATH_INFO *source, PATH_INFO *dest, LOG_INFO *LogInfo); void SW_F_init_ptrs(char *InFiles[]); -void SW_F_construct(const char *firstfile, char _ProjDir[], LOG_INFO *LogInfo); +void SW_F_construct( + const char *firstfile, char SW_ProjDir[], LOG_INFO *LogInfo +); void SW_F_deconstruct(char *InFiles[]); diff --git a/include/SW_Flow_lib.h b/include/SW_Flow_lib.h index d027f94ce..f8b311600 100644 --- a/include/SW_Flow_lib.h +++ b/include/SW_Flow_lib.h @@ -92,10 +92,10 @@ void infiltrate_water_high( double drain[], double *drainout, double pptleft, - int nlyrs, - double swcfc[], + unsigned int nlyrs, + const double swcfc[], double swcsat[], - double impermeability[], + const double impermeability[], double *standingWater, double lyrFrozen[] ); @@ -105,7 +105,7 @@ void transp_weighted_avg( SW_SITE *SW_Site, unsigned int n_tr_rgns, LyrIndex n_layers, - unsigned int tr_regions[], + const unsigned int tr_regions[], double swc[], int VegType, LOG_INFO *LogInfo @@ -190,7 +190,7 @@ void remove_from_soil( SW_SITE *SW_Site, double *aet, unsigned int nlyrs, - double coeff[], + const double coeff[], double rate, double swcmin[], double lyrFrozen[], @@ -215,7 +215,7 @@ void hydraulic_redistribution( SW_SITE *SW_Site, unsigned int vegk, unsigned int nlyrs, - double lyrFrozen[], + const double lyrFrozen[], double maxCondroot, double swp50, double shapeCond, @@ -281,8 +281,8 @@ void lyrTemp_to_lyrSoil_temperature( void lyrSoil_to_lyrTemp_temperature( unsigned int nlyrSoil, - double depth_Soil[], - double avgLyrTemp[], + const double depth_Soil[], + const double avgLyrTemp[], double endTemp, unsigned int nlyrTemp, double depth_Temp[], @@ -293,8 +293,8 @@ void lyrSoil_to_lyrTemp_temperature( void lyrSoil_to_lyrTemp( double cor[MAX_ST_RGR][MAX_LAYERS + 1], unsigned int nlyrSoil, - double width_Soil[], - double var[], + const double width_Soil[], + const double var[], unsigned int nlyrTemp, double width_Temp, double res[] @@ -324,8 +324,8 @@ void soil_temperature_setup( double avgLyrTempInit[], double sTconst, unsigned int nlyrs, - double fc[], - double wp[], + const double fc[], + const double wp[], double deltaX, double theMaxDepth, unsigned int nRgr, @@ -340,18 +340,18 @@ void set_frozen_unfrozen( double avgLyrTemp[], double swc[], double swc_sat[], - double width[], + const double width[], double lyrFrozen[] ); unsigned int adjust_Tsoil_by_freezing_and_thawing( - double oldavgLyrTemp[], - double avgLyrTemp[], + const double oldavgLyrTemp[], + const double avgLyrTemp[], double shParam, unsigned int nlyrs, - double vwc[], - double bDensity[], - Bool fusion_pool_init, + const double vwc[], + const double bDensity[], + Bool *fusion_pool_init, double oldsFusionPool_actual[] ); @@ -360,20 +360,20 @@ void soil_temperature_today( double deltaX, double sT1, double sTconst, - int nRgr, + unsigned int nRgr, double avgLyrTempR[], - double oldavgLyrTempR[], - double vwcR[], - double wpR[], - double fcR[], - double bDensityR[], + const double oldavgLyrTempR[], + const double vwcR[], + const double wpR[], + const double fcR[], + const double bDensityR[], double csParam1, double csParam2, double shParam, Bool *ptr_stError, double surface_range, double temperatureRangeR[], - double depthsR[], + const double depthsR[], TimeInt year, TimeInt doy ); diff --git a/include/SW_Main_lib.h b/include/SW_Main_lib.h index 8c9123fee..5385c12c8 100644 --- a/include/SW_Main_lib.h +++ b/include/SW_Main_lib.h @@ -22,7 +22,7 @@ void sw_init_args( int argc, char **argv, Bool *EchoInits, - char **_firstfile, + char **firstfile, unsigned long *userSUID, double *wallTimeLimit, Bool *renameDomainTemplateNC, diff --git a/include/SW_Markov.h b/include/SW_Markov.h index cb29c2226..07f78ae6a 100644 --- a/include/SW_Markov.h +++ b/include/SW_Markov.h @@ -13,7 +13,6 @@ #ifndef SW_MARKOV_H #define SW_MARKOV_H -#include "include/generic.h" // for RealD #include "include/SW_datastructs.h" // for SW_MARKOV, LOG_INFO #include "include/SW_Defines.h" // for TimeInt @@ -43,7 +42,7 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo); void SW_MKV_setup( SW_MARKOV *SW_Markov, unsigned long Weather_rng_seed, - int Weather_genWeathMethod, + unsigned int Weather_genWeathMethod, char *InFiles[], LOG_INFO *LogInfo ); @@ -52,9 +51,9 @@ void SW_MKV_today( SW_MARKOV *SW_Markov, TimeInt doy0, TimeInt year, - RealD *tmax, - RealD *tmin, - RealD *rain, + double *tmax, + double *tmin, + double *rain, LOG_INFO *LogInfo ); diff --git a/include/SW_Output.h b/include/SW_Output.h index 2819ef913..85a42b0a6 100644 --- a/include/SW_Output.h +++ b/include/SW_Output.h @@ -147,10 +147,10 @@ extern "C" { /* Externed Global Variables */ /* --------------------------------------------------- */ -extern char const *key2str[]; -extern char const *pd2longstr[]; -extern char const *styp2str[]; -extern char const *styp2longstr[]; +extern const char *const key2str[]; +extern const char *const pd2longstr[]; +extern const char *const styp2str[]; +extern const char *const styp2longstr[]; /* =================================================== */ /* Global Function Declarations */ @@ -164,20 +164,18 @@ void SW_OUTDOM_construct(SW_OUT_DOM *OutDom); void SW_OUT_construct( Bool zeroOutStruct, - Bool make_soil[], - Bool make_regular[], + SW_FILE_STATUS *FileStatus, SW_OUT_DOM *OutDom, SW_OUT_RUN *OutRun, - LyrIndex n_layers, LOG_INFO *LogInfo ); void SW_OUT_deconstruct(Bool full_reset, SW_RUN *sw); void SW_OUT_set_ncol( - int tLayers, - int n_evap_lyrs, - int nTaxaEstabl, + unsigned int tLayers, + unsigned int n_evap_lyrs, + unsigned int nTaxaEstabl, IntUS ncol_OUT[], IntUS nvar_OUT[], IntUS nsl_OUT[][SW_OUTNMAXVARS], @@ -185,16 +183,16 @@ void SW_OUT_set_ncol( ); void SW_OUT_set_colnames( - int tLayers, + unsigned int tLayers, SW_VEGESTAB_INFO **parms, - IntUS ncol_OUT[], + const IntUS ncol_OUT[], char *colnames_OUT[][5 * NVEGTYPES + MAX_LAYERS], LOG_INFO *LogInfo ); void SW_OUT_setup_output( - int tLayers, - int n_evap_lyrs, + unsigned int tLayers, + unsigned int n_evap_lyrs, SW_VEGESTAB *SW_VegEstab, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo @@ -235,14 +233,18 @@ void SW_OUT_sum_today( ); void SW_OUT_write_today( - SW_RUN *sw, SW_OUT_DOM *OutDom, Bool bFlush_output, TimeInt tOffset + SW_RUN *sw, + SW_OUT_DOM *OutDom, + Bool bFlush_output, + TimeInt tOffset, + LOG_INFO *LogInfo ); void SW_OUT_write_year(void); void SW_OUT_flush(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo); -void _collect_values( +void collect_values( SW_RUN *sw, SW_OUT_DOM *OutDom, Bool bFlush_output, @@ -258,9 +260,9 @@ void SW_OUT_create_files( SW_FILE_STATUS *SW_FileStatus, SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo ); -void _echo_outputs(SW_OUT_DOM *OutDom); +void echo_outputs(SW_OUT_DOM *OutDom); -void _echo_all_inputs(SW_RUN *sw, SW_OUT_DOM *OutDom); +void echo_all_inputs(SW_RUN *sw, SW_OUT_DOM *OutDom); void find_OutPeriods_inUse(SW_OUT_DOM *OutDom); diff --git a/include/SW_Output_outarray.h b/include/SW_Output_outarray.h index ffd22c232..0e4c65147 100644 --- a/include/SW_Output_outarray.h +++ b/include/SW_Output_outarray.h @@ -16,7 +16,7 @@ #ifndef SW_OUTPUT_ARRAY_H #define SW_OUTPUT_ARRAY_H -#include "include/generic.h" // for Bool, RealD +#include "include/generic.h" // for Bool #include "include/SW_datastructs.h" // for SW_MODEL, L... #include "include/SW_Defines.h" // for OutPeriod, SW_OUTNPERIODS, SW_OUTN... #include // for size_t @@ -110,7 +110,7 @@ extern const IntUS ncol_TimeOUT[SW_OUTNPERIODS]; /* Global Function Declarations */ /* --------------------------------------------------- */ void SW_OUT_set_nrow( - SW_MODEL *SW_Model, Bool use_OutPeriod[], size_t nrow_OUT[] + SW_MODEL *SW_Model, const Bool use_OutPeriod[], size_t nrow_OUT[] ); void SW_OUT_construct_outarray( @@ -123,20 +123,20 @@ void SW_OUT_deconstruct_outarray(SW_OUT_RUN *OutRun); void get_outvalleader( SW_MODEL *SW_Model, OutPeriod pd, - size_t irow_OUT[], - size_t nrow_OUT[], + const size_t irow_OUT[], + const size_t nrow_OUT[], TimeInt tOffset, - RealD *p + double *p ); #endif #if defined(STEPWAT) -void do_running_agg(RealD *p, RealD *psd, size_t k, IntU n, RealD x); +void do_running_agg(double *p, double *psd, size_t k, IntU n, double x); #endif void SW_OUT_calc_iOUToffset( - size_t nrow_OUT[], - IntUS nvar_OUT[], + const size_t nrow_OUT[], + const IntUS nvar_OUT[], IntUS nsl_OUT[][SW_OUTNMAXVARS], IntUS npft_OUT[][SW_OUTNMAXVARS], size_t iOUToffset[][SW_OUTNPERIODS][SW_OUTNMAXVARS] diff --git a/include/SW_Output_outtext.h b/include/SW_Output_outtext.h index 43a1557be..373529749 100644 --- a/include/SW_Output_outtext.h +++ b/include/SW_Output_outtext.h @@ -70,8 +70,8 @@ void write_headers_to_csv( FILE *fp_reg, FILE *fp_soil, Bool does_agg, - Bool make_regular[], - Bool make_soil[], + const Bool make_regular[], + const Bool make_soil[], LyrIndex n_layers, LOG_INFO *LogInfo ); @@ -79,7 +79,7 @@ void write_headers_to_csv( void find_TXToutputSoilReg_inUse( Bool make_soil[], Bool make_regular[], - Bool has_sl[], + const Bool has_sl[], OutPeriod timeSteps[][SW_OUTNPERIODS], IntUS used_OUTNPERIODS ); diff --git a/include/SW_Site.h b/include/SW_Site.h index 8f32772f9..f97183486 100644 --- a/include/SW_Site.h +++ b/include/SW_Site.h @@ -83,7 +83,7 @@ swcBulk_atSWPcrit[SW_FORBS], and my_transp_rgn[SW_FORBS] to SW_LAYER_INFO #ifndef SW_SITE_H #define SW_SITE_H -#include "include/generic.h" // for Bool, RealD, RealF +#include "include/generic.h" // for Bool #include "include/SW_datastructs.h" // for SW_SITE, SW_VEGPROD, LOG_INFO #include "include/SW_Defines.h" // for LyrIndex @@ -191,8 +191,8 @@ extern "C" { /* =================================================== */ /* Externed Global Variables */ /* --------------------------------------------------- */ -extern char const *swrc2str[]; -extern char const *ptf2str[]; +extern const char *const swrc2str[]; +extern const char *const ptf2str[]; /* =================================================== */ @@ -234,7 +234,7 @@ Bool SWRC_check_parameters_for_FXW(double *swrcp, LOG_INFO *LogInfo); double SW_swcBulk_saturated( unsigned int swrc_type, - double *swrcp, + const double *swrcp, double gravel, double width, unsigned int ptf_type, @@ -253,7 +253,7 @@ double SW_swcBulk_minimum( double sand, double clay, double swcBulk_sat, - RealD _SWCMinVal, + double SWCMinVal, LOG_INFO *LogInfo ); @@ -270,18 +270,18 @@ void PTF_RawlsBrakensiek1985( ); -RealD calculate_soilBulkDensity(RealD matricDensity, RealD fractionGravel); +double calculate_soilBulkDensity(double matricDensity, double fractionGravel); -RealD calculate_soilMatricDensity( - RealD bulkDensity, RealD fractionGravel, LOG_INFO *LogInfo +double calculate_soilMatricDensity( + double bulkDensity, double fractionGravel, LOG_INFO *LogInfo ); -LyrIndex nlayers_bsevap(RealD *evap_coeff, LyrIndex n_layers); +LyrIndex nlayers_bsevap(double *evap_coeff, LyrIndex n_layers); void nlayers_vegroots( LyrIndex n_layers, LyrIndex n_transp_lyrs[], - RealD transp_coeff[][MAX_LAYERS] + double transp_coeff[][MAX_LAYERS] ); void SW_SIT_construct(SW_SITE *SW_Site); @@ -296,7 +296,7 @@ void SW_SIT_init_run( SW_VEGPROD *SW_VegProd, SW_SITE *SW_Site, LOG_INFO *LogInfo ); -void _echo_inputs(SW_SITE *SW_Site, SW_MODEL *SW_Model); +void echo_inputs(SW_SITE *SW_Site, SW_MODEL *SW_Model); /* these used to be in Layers */ @@ -310,25 +310,28 @@ void set_soillayers( SW_VEGPROD *SW_VegProd, SW_SITE *SW_Site, LyrIndex nlyrs, - RealF *dmax, - RealF *bd, - RealF *f_gravel, - RealF *evco, - RealF *trco_grass, - RealF *trco_shrub, - RealF *trco_tree, - RealF *trco_forb, - RealF *psand, - RealF *pclay, - RealF *imperm, - RealF *soiltemp, + const double *dmax, + const double *bd, + const double *f_gravel, + const double *evco, + const double *trco_grass, + const double *trco_shrub, + const double *trco_tree, + const double *trco_forb, + const double *psand, + const double *pclay, + const double *imperm, + const double *soiltemp, int nRegions, - RealD *regionLowerBounds, + double *regionLowerBounds, LOG_INFO *LogInfo ); void derive_soilRegions( - SW_SITE *SW_Site, int nRegions, RealD *regionLowerBounds, LOG_INFO *LogInfo + SW_SITE *SW_Site, + unsigned int nRegions, + const double *regionLowerBounds, + LOG_INFO *LogInfo ); diff --git a/include/SW_Sky.h b/include/SW_Sky.h index 8eda3399b..6ea9e4b29 100644 --- a/include/SW_Sky.h +++ b/include/SW_Sky.h @@ -17,7 +17,7 @@ Purpose: Support definitions for Sky.c, Weather.c, etc. estimate snow depth 09/26/2011 (drs) added a daily variable for each monthly input in struct -SW_SKY: RealD cloudcov_daily, windspeed_daily, r_humidity_daily, +SW_SKY: double cloudcov_daily, windspeed_daily, r_humidity_daily, transmission_daily, snow_density_daily each of [MAX_DAYS] */ /********************************************************/ @@ -26,7 +26,6 @@ transmission_daily, snow_density_daily each of [MAX_DAYS] #ifndef SW_SKY_H #define SW_SKY_H -#include "include/generic.h" // for RealD #include "include/SW_datastructs.h" // for LOG_INFO, SW_MODEL, SW_SKY #include "include/SW_Defines.h" // for MAX_MONTHS @@ -40,8 +39,8 @@ extern "C" { void SW_SKY_read(char *InFiles[], SW_SKY *SW_Sky, LOG_INFO *LogInfo); void SW_SKY_new_year( SW_MODEL *SW_Model, - RealD snow_density[MAX_MONTHS], - RealD snow_density_daily[MAX_MONTHS] + double snow_density[MAX_MONTHS], + double snow_density_daily[MAX_MONTHS] ); #ifdef __cplusplus diff --git a/include/SW_SoilWater.h b/include/SW_SoilWater.h index 36d5b0749..ae512b464 100644 --- a/include/SW_SoilWater.h +++ b/include/SW_SoilWater.h @@ -101,7 +101,6 @@ extern "C" { #endif -#include "include/generic.h" // for RealD #include "include/SW_datastructs.h" // for SW_SOILWAT, SW_SITE, LOG_INFO #include "include/SW_Defines.h" // for TimeInt, LyrIndex, NVEGTYPES, MAX_... @@ -137,10 +136,10 @@ void SW_SWC_read( ); void SW_SWC_init_run( - SW_SOILWAT *SW_SoilWat, SW_SITE *SW_Site, RealD *temp_snow + SW_SOILWAT *SW_SoilWat, SW_SITE *SW_Site, double *temp_snow ); -void _read_swc_hist( +void read_swc_hist( SW_SOILWAT_HIST *SoilWat_hist, TimeInt year, LOG_INFO *LogInfo ); @@ -148,14 +147,14 @@ void SW_SWC_water_flow(SW_RUN *sw, LOG_INFO *LogInfo); void calculate_repartitioned_soilwater( SW_SOILWAT *SW_SoilWat, - RealD swcBulk_atSWPcrit[][MAX_LAYERS], + double swcBulk_atSWPcrit[][MAX_LAYERS], SW_VEGPROD *SW_VegProd, LyrIndex n_layers ); void SW_SWC_adjust_swc( - RealD swcBulk[][MAX_LAYERS], - RealD swcBulk_min[], + double swcBulk[][MAX_LAYERS], + double swcBulk_min[], TimeInt doy, SW_SOILWAT_HIST SoilWat_hist, LyrIndex n_layers, @@ -163,33 +162,33 @@ void SW_SWC_adjust_swc( ); void SW_SWC_adjust_snow( - RealD *temp_snow, - RealD snowpack[], + double *temp_snow, + double snowpack[], SW_SITE *SW_Site, - RealD temp_min, - RealD temp_max, - RealD ppt, + double temp_min, + double temp_max, + double ppt, TimeInt doy, - RealD *rain, - RealD *snow, - RealD *snowmelt + double *rain, + double *snow, + double *snowmelt ); -RealD SW_SWC_snowloss(RealD pet, RealD *snowpack); +double SW_SWC_snowloss(double pet, double *snowpack); -RealD SW_SnowDepth(RealD SWE, RealD snowdensity); +double SW_SnowDepth(double SWE, double snowdensity); void SW_SWC_end_day(SW_SOILWAT *SW_SoilWat, LyrIndex n_layers); void get_dSWAbulk( - int i, + unsigned int i, SW_VEGPROD *SW_VegProd, - RealF swa_master[][NVEGTYPES][MAX_LAYERS], - RealF dSWA_repart_sum[][MAX_LAYERS] + double swa_master[][NVEGTYPES][MAX_LAYERS], + double dSWA_repart_sum[][MAX_LAYERS] ); -RealD SW_SWRC_SWCtoSWP( - RealD swcBulk, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo +double SW_SWRC_SWCtoSWP( + double swcBulk, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo ); double SWRC_SWCtoSWP( @@ -228,8 +227,8 @@ double SWRC_SWCtoSWP_FXW( LOG_INFO *LogInfo ); -RealD SW_SWRC_SWPtoSWC( - RealD swpMatric, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo +double SW_SWRC_SWPtoSWC( + double swpMatric, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo ); double SWRC_SWPtoSWC( @@ -247,7 +246,7 @@ double SWRC_SWPtoSWC_Campbell1974( ); double SWRC_SWPtoSWC_vanGenuchten1980( - double swpMatric, double *swrcp, double gravel, double width + double swpMatric, const double *swrcp, double gravel, double width ); double SWRC_SWPtoSWC_FXW( diff --git a/include/SW_VegEstab.h b/include/SW_VegEstab.h index ee2da5e6e..0d1aecd71 100644 --- a/include/SW_VegEstab.h +++ b/include/SW_VegEstab.h @@ -15,7 +15,7 @@ #ifndef SW_VEGESTAB_H #define SW_VEGESTAB_H -#include "include/generic.h" // for Bool, RealD, IntU +#include "include/generic.h" // for Bool, IntU #include "include/SW_datastructs.h" // for SW_VEGESTAB, SW_VEGESTAB_INFO, SW_... #include "include/SW_Defines.h" // for LyrIndex, TimeInt @@ -33,7 +33,10 @@ extern "C" { /* Global Function Declarations */ /* --------------------------------------------------- */ void SW_VES_read( - SW_VEGESTAB *SW_VegEstab, char *InFiles[], char *_ProjDir, LOG_INFO *LogInfo + SW_VEGESTAB *SW_VegEstab, + char *InFiles[], + char *SW_ProjDir, + LOG_INFO *LogInfo ); void SW_VES_read2( @@ -41,7 +44,7 @@ void SW_VES_read2( Bool use_VegEstab, Bool consider_InputFlag, char *InFiles[], - char *_ProjDir, + char *SW_ProjDir, LOG_INFO *LogInfo ); @@ -66,7 +69,7 @@ void SW_VES_init_run( void SW_VES_checkestab( SW_VEGESTAB_INFO **parms, SW_WEATHER *SW_Weather, - RealD swcBulk[][MAX_LAYERS], + double swcBulk[][MAX_LAYERS], TimeInt doy, TimeInt firstdoy, IntU count @@ -74,7 +77,7 @@ void SW_VES_checkestab( void SW_VES_new_year(IntU count); -void _spp_init( +void spp_init( SW_VEGESTAB_INFO **parms, unsigned int sppnum, SW_SITE *SW_Site, @@ -82,9 +85,9 @@ void _spp_init( LOG_INFO *LogInfo ); -IntU _new_species(SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo); +IntU new_species(SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo); -void _echo_VegEstab(RealD width[], SW_VEGESTAB_INFO **parms, IntU count); +void echo_VegEstab(const double width[], SW_VEGESTAB_INFO **parms, IntU count); /* COMMENT-1 diff --git a/include/SW_VegProd.h b/include/SW_VegProd.h index 8800a2ac2..b91926b52 100644 --- a/include/SW_VegProd.h +++ b/include/SW_VegProd.h @@ -83,7 +83,7 @@ #ifndef SW_VEGPROD_H #define SW_VEGPROD_H -#include "include/generic.h" // for Bool, RealD +#include "include/generic.h" // for Bool #include "include/SW_datastructs.h" // for SW_VEGPROD, SW_MODEL, SW_WEATHER_HIST #include "include/SW_Defines.h" // for LyrIndex, NVEGTYPES, MAX_LAYERS, @@ -102,7 +102,7 @@ extern "C" { /* =================================================== */ /* Externed Global Variables */ /* --------------------------------------------------- */ -extern char const *key2veg[NVEGTYPES]; +extern const char *const key2veg[NVEGTYPES]; /* =================================================== */ @@ -131,7 +131,7 @@ void estimatePotNatVegComposition( double meanTemp_C, double PPT_cm, double meanTempMon_C[], - double PPTMon_cm[], + const double PPTMon_cm[], double inputValues[], double shrubLimit, double SumGrassesFraction, @@ -149,8 +149,8 @@ void estimatePotNatVegComposition( double cutZeroInf(double testValue); void uniqueIndices( - int arrayOne[], - int arrayTwo[], + const int arrayOne[], + const int arrayTwo[], int arrayOneSize, int arrayTwoSize, int *finalIndexArray, @@ -168,12 +168,12 @@ void SW_VPD_init_run( void SW_VPD_deconstruct(SW_VEGPROD *SW_VegProd); void apply_biomassCO2effect( - double *new_biomass, double *biomass, double multiplier + double *new_biomass, const double *biomass, double multiplier ); -RealD sum_across_vegtypes(RealD x[][MAX_LAYERS], LyrIndex layerno); +double sum_across_vegtypes(double x[][MAX_LAYERS], LyrIndex layerno); -void _echo_VegProd(VegType VegProd_veg[], CoverType VegProd_bare_cov); +void echo_VegProd(VegType VegProd_veg[], CoverType VegProd_bare_cov); void get_critical_rank(SW_VEGPROD *SW_VegProd); diff --git a/include/SW_Weather.h b/include/SW_Weather.h index 8774d3430..8b34961b6 100644 --- a/include/SW_Weather.h +++ b/include/SW_Weather.h @@ -37,7 +37,7 @@ #ifndef SW_WEATHER_H #define SW_WEATHER_H -#include "include/generic.h" // for Bool, RealD +#include "include/generic.h" // for Bool #include "include/SW_datastructs.h" // for SW_WEATHER, SW_SKY, SW_MODEL, LOG_... #include "include/SW_Defines.h" // for TimeInt @@ -58,7 +58,7 @@ extern "C" { void SW_WTH_setup( SW_WEATHER *SW_Weather, char *InFiles[], - char *_weather_prefix, + char *weather_prefix, LOG_INFO *LogInfo ); @@ -70,7 +70,7 @@ void SW_WTH_read( ); void set_dailyInputIndices( - Bool dailyInputFlags[MAX_INPUT_COLUMNS], + const Bool dailyInputFlags[MAX_INPUT_COLUMNS], unsigned int dailyInputIndices[MAX_INPUT_COLUMNS], unsigned int *n_input_forcings ); @@ -85,7 +85,7 @@ void check_and_update_dailyInputFlags( void averageClimateAcrossYears( SW_CLIMATE_YEARLY *climateOutput, - int numYears, + unsigned int numYears, SW_CLIMATE_CLIM *climateAverages ); @@ -93,8 +93,8 @@ void calcSiteClimate( SW_WEATHER_HIST **allHist, TimeInt cum_monthdays[], TimeInt days_in_month[], - int numYears, - int startYear, + unsigned int numYears, + unsigned int startYear, Bool inNorthHem, SW_CLIMATE_YEARLY *climateOutput ); @@ -103,13 +103,13 @@ void calcSiteClimateLatInvariants( SW_WEATHER_HIST **allHist, TimeInt cum_monthdays[], TimeInt days_in_month[], - int numYears, - int startYear, + unsigned int numYears, + unsigned int startYear, SW_CLIMATE_YEARLY *climateOutput ); void findDriestQtr( - int numYears, + unsigned int numYears, Bool inNorthHem, double *meanTempDriestQtr_C, double **meanTempMon_C, @@ -117,13 +117,13 @@ void findDriestQtr( ); void driestQtrSouthAdjMonYears( - int month, - int *adjustedYearZero, - int *adjustedYearOne, - int *adjustedYearTwo, - int *adjustedMonth, - int *prevMonth, - int *nextMonth + unsigned int month, + unsigned int *adjustedYearZero, + unsigned int *adjustedYearOne, + unsigned int *adjustedYearTwo, + unsigned int *adjustedMonth, + unsigned int *prevMonth, + unsigned int *nextMonth ); void initializeClimatePtrs( @@ -133,7 +133,7 @@ void initializeClimatePtrs( void initializeMonthlyClimatePtrs(SW_CLIMATE_YEARLY *climateOutput); void allocateClimateStructs( - int numYears, + unsigned int numYears, SW_CLIMATE_YEARLY *climateOutput, SW_CLIMATE_CLIM *climateAverages, LOG_INFO *LogInfo @@ -143,19 +143,19 @@ void deallocateClimateStructs( SW_CLIMATE_YEARLY *climateOutput, SW_CLIMATE_CLIM *climateAverages ); -void _read_weather_hist( +void read_weather_hist( TimeInt year, SW_WEATHER_HIST *yearWeather, char weather_prefix[], unsigned int n_input_forcings, - unsigned int *dailyInputIndices, - Bool *dailyInputFlags, + const unsigned int *dailyInputIndices, + const Bool *dailyInputFlags, LOG_INFO *LogInfo ); void readAllWeather( SW_WEATHER_HIST **allHist, - int startYear, + unsigned int startYear, unsigned int n_years, Bool use_weathergenerator_only, char weather_prefix[], @@ -165,9 +165,9 @@ void readAllWeather( unsigned int n_input_forcings, unsigned int *dailyInputIndices, Bool *dailyInputFlags, - RealD *cloudcov, - RealD *windspeed, - RealD *r_humidity, + double *cloudcov, + double *windspeed, + double *r_humidity, TimeInt cum_monthdays[], TimeInt days_in_month[], LOG_INFO *LogInfo @@ -183,16 +183,16 @@ void finalizeAllWeather( void scaleAllWeather( SW_WEATHER_HIST **allHist, - int startYear, + unsigned int startYear, unsigned int n_years, double *scale_temp_max, double *scale_temp_min, double *scale_precip, double *scale_skyCover, - double *scale_wind, + const double *scale_wind, double *scale_rH, - double *scale_actVapPress, - double *scale_shortWaveRad, + const double *scale_actVapPress, + const double *scale_shortWaveRad, TimeInt cum_monthdays[], TimeInt days_in_month[] ); @@ -200,7 +200,7 @@ void scaleAllWeather( void generateMissingWeather( SW_MARKOV *SW_Markov, SW_WEATHER_HIST **allHist, - int startYear, + unsigned int startYear, unsigned int n_years, unsigned int method, unsigned int optLOCF_nMax, @@ -217,7 +217,7 @@ void initializeAllWeatherPtrs(SW_WEATHER_HIST **allHist, unsigned int n_years); void deallocateAllWeather(SW_WEATHER_HIST **allHist, unsigned int n_years); -void _clear_hist_weather(SW_WEATHER_HIST *yearWeather); +void clear_hist_weather(SW_WEATHER_HIST *yearWeather); void SW_WTH_finalize_all_weather( SW_MARKOV *SW_Markov, @@ -240,7 +240,7 @@ void SW_WTH_deconstruct(SW_WEATHER *SW_Weather); void SW_WTH_new_day( SW_WEATHER *SW_Weather, SW_SITE *SW_Site, - RealD snowpack[], + double snowpack[], TimeInt doy, TimeInt year, LOG_INFO *LogInfo diff --git a/include/SW_datastructs.h b/include/SW_datastructs.h index b8d5fc84d..6cfc6dde2 100644 --- a/include/SW_datastructs.h +++ b/include/SW_datastructs.h @@ -144,9 +144,9 @@ typedef struct { firstdoy, /* start day for this year */ lastdoy, /* 366 if leapyear or endend if endyr */ doy, week, month, year, simyear, /* current model time */ - _prevweek, /* check for new week */ - _prevmonth, /* check for new month */ - _prevyear; /* check for new year */ + prevweek, /* check for new week */ + prevmonth, /* check for new month */ + prevyear; /* check for new year */ /* however, week and month are base0 because they * are used as array indices, so take care. * doy and year are base1. */ @@ -164,9 +164,9 @@ typedef struct { // ********** END of copying SW_DOMAIN's data ************* - RealD longitude, /* longitude of the site (radians) */ - latitude, /* latitude of the site (radians) */ - elevation, /* elevation a.s.l (m) of the site */ + double longitude, /* longitude of the site (radians) */ + latitude, /* latitude of the site (radians) */ + elevation, /* elevation a.s.l (m) of the site */ slope, /* slope of the site (radians): between 0 (horizontal) and pi / 2 (vertical) */ aspect; /* aspect of the site (radians): A value of \ref SW_MISSING @@ -227,7 +227,7 @@ typedef struct { #if defined(SWNETCDF) char **ncOutFiles[SW_OUTNKEYS][SW_OUTNPERIODS]; - int numOutFiles; + unsigned int numOutFiles; #endif } SW_FILE_STATUS; @@ -254,8 +254,8 @@ typedef struct { n_transp_lyrs[NVEGTYPES], /* layer index of deepest transp. region */ deep_lyr; /* index of deep drainage layer if deepdrain, 0 otherwise */ - RealD slow_drain_coeff, /* low soil water drainage coefficient */ - pet_scale, /* changes relative effect of PET calculation */ + double slow_drain_coeff, /* low soil water drainage coefficient */ + pet_scale, /* changes relative effect of PET calculation */ /* SWAT2K model parameters : Neitsch S, Arnold J, Kiniry J, Williams J. 2005. Soil and water assessment tool (SWAT) theoretical documentation. version 2005. Blackland Research Center, Texas @@ -304,17 +304,17 @@ typedef struct { /* transpiration regions shallow, moderately shallow, */ /* deep and very deep. units are in layer numbers. */ - LyrIndex _TranspRgnBounds[MAX_TRANSP_REGIONS]; - RealD _SWCInitVal, /* initialization value for swc */ - _SWCWetVal, /* value for a "wet" day, */ - _SWCMinVal; /* lower bound on swc. */ + LyrIndex TranspRgnBounds[MAX_TRANSP_REGIONS]; + double SWCInitVal, /* initialization value for swc */ + SWCWetVal, /* value for a "wet" day, */ + SWCMinVal; /* lower bound on swc. */ /* bulk = relating to the whole soil, i.e., matric + rock/gravel/coarse * fragments */ /* matric = relating to the < 2 mm fraction of the soil, i.e., sand, clay, * and silt */ - RealD + double /* Inputs */ width[MAX_LAYERS], /* width of the soil layer (cm) */ soilDensityInput[MAX_LAYERS], /* soil density [g / cm3]: either of the @@ -377,7 +377,7 @@ typedef struct { `swrcp` but we need to loop over soil layers for every vegetation type in `my_transp_rng` */ - RealD swrcp[MAX_LAYERS][SWRC_PARAM_NMAX]; + double swrcp[MAX_LAYERS][SWRC_PARAM_NMAX]; /**< Parameters of SWRC: parameter interpretation varies with selected SWRC, * see `SWRC_check_parameters()` */ LyrIndex my_transp_rgn[NVEGTYPES][MAX_LAYERS]; /* which transp zones from @@ -391,7 +391,7 @@ typedef struct { /** Data type that describes cover attributes of a surface type */ typedef struct { - RealD + double /** The cover contribution to the total plot [0-1]; user input from file `Input/veg.in` */ fCover, @@ -414,14 +414,14 @@ typedef struct { /** Constant canopy height: if > 0 then constant canopy height [cm] and overriding cnpy-tangens = f(biomass); user input from file `Input/veg.in` */ - RealD canopy_height_constant; + double canopy_height_constant; tanfunc_t /** Shading effect on transpiration based on live and dead biomass; user input from file `Input/veg.in` */ tr_shade_effects; - RealD + double /** Parameter of live and dead biomass shading effects; user input from file `Input/veg.in` */ shade_scale, @@ -429,7 +429,7 @@ typedef struct { user input from file `Input/veg.in` */ shade_deadmax; - RealD + double /** Monthly litter amount [g / m2] as if this vegetation type covers 100% of the simulated surface; user input from file `Input/veg.in` */ litter[MAX_MONTHS], @@ -444,7 +444,7 @@ typedef struct { user input from file `Input/veg.in` */ lai_conv[MAX_MONTHS]; - RealD + double /** Daily litter amount [g / m2] */ litter_daily[MAX_DAYS + 1], /** Daily aboveground biomass [g / m2] */ @@ -472,7 +472,7 @@ typedef struct { user input from file `Input/veg.in` */ flagHydraulicRedistribution; - RealD + double /** Parameter for hydraulic redistribution: maximum radial soil-root conductance of the entire active root system for water [cm / (-bar * day)]; @@ -488,13 +488,13 @@ typedef struct { user input from file `Input/veg.in` */ shapeCond; - RealD + double /** Critical soil water potential below which vegetation cannot sustain transpiration [-bar]; user input from file `Input/veg.in` */ SWPcrit; - RealD + double /** Parameter for vegetation interception; user input from file `Input/veg.in` */ veg_kSmax, @@ -505,7 +505,7 @@ typedef struct { user input from file `Input/veg.in` */ lit_kSmax; - RealD + double /** Parameter for partitioning potential rates of bare-soil evaporation and transpiration; user input from file `Input/veg.in` */ @@ -514,7 +514,7 @@ typedef struct { user input from file `Input/veg.in` */ Es_param_limit; - RealD + double /** Parameter for CO2-effects on biomass; user input from file `Input/veg.in` */ co2_bio_coeff1, @@ -528,7 +528,7 @@ typedef struct { user input from file `Input/veg.in` */ co2_wue_coeff2; - RealD + double /** Calculated multipliers for CO2-effects: - column \ref BIO_INDEX holds biomass multipliers - column \ref WUE_INDEX holds water-use-efficiency multipliers @@ -541,14 +541,14 @@ typedef struct { // biomass [g/m2] per vegetation type as observed in total vegetation // (reduced from 100% cover per vegtype (inputs) to actual cover // (simulated)) - RealD biomass_inveg, biolive_inveg, litter_inveg; + double biomass_inveg, biolive_inveg, litter_inveg; } VegTypeOut; typedef struct { // biomass [g/m2] per vegetation type as observed in total vegetation VegTypeOut veg[NVEGTYPES]; // biomass [g/m2] of total vegetation - RealD biomass_total, biolive_total, litter_total, LAI; + double biomass_total, biolive_total, litter_total, LAI; } SW_VEGPROD_OUTPUTS; /** Data type to describe the surface cover of a SOILWAT2 simulation run */ @@ -565,7 +565,7 @@ typedef struct { user input from file `Input/outsetup.in` */ use_SWA; - RealD + double // storing values in same order as defined in STEPWAT2/rgroup.in // (0=tree, 1=shrub, 2=grass, 3=forb) critSoilWater[NVEGTYPES]; @@ -619,23 +619,23 @@ typedef struct { typedef struct { /* Weather values of the current simulation day */ - RealD temp_avg, temp_max, temp_min, ppt, rain, cloudCover, windSpeed, + double temp_avg, temp_max, temp_min, ppt, rain, cloudCover, windSpeed, relHumidity, shortWaveRad, actualVaporPressure; } SW_WEATHER_NOW; typedef struct { /* Daily weather values for one year */ - RealD temp_max[MAX_DAYS], temp_min[MAX_DAYS], temp_avg[MAX_DAYS], + double temp_max[MAX_DAYS], temp_min[MAX_DAYS], temp_avg[MAX_DAYS], ppt[MAX_DAYS], cloudcov_daily[MAX_DAYS], windspeed_daily[MAX_DAYS], r_humidity_daily[MAX_DAYS], shortWaveRad[MAX_DAYS], actualVaporPressure[MAX_DAYS]; - // RealD temp_month_avg[MAX_MONTHS], temp_year_avg; // currently not used + // double temp_month_avg[MAX_MONTHS], temp_year_avg; // currently not used } SW_WEATHER_HIST; /* accumulators for output values hold only the */ /* current period's values (eg, weekly or monthly) */ typedef struct { - RealD temp_max, temp_min, temp_avg, ppt, rain, snow, snowmelt, + double temp_max, temp_min, temp_avg, ppt, rain, snow, snowmelt, snowloss, /* 20091015 (drs) ppt is divided into rain and snow */ snowRunoff, surfaceRunoff, surfaceRunon, soil_inf, et, aet, pet, surfaceAvg, surfaceMax, surfaceMin; @@ -652,7 +652,7 @@ dimension represents year. @note Number of years is variable and determined at runtime. */ typedef struct { - RealD * + double * *PPTMon_cm, /**< 2D array containing monthly amount precipitation [cm]*/ *PPT_cm, /**< Array containing annual precipitation amount [cm]*/ *PPT7thMon_mm, /**< Array containing July precipitation amount in July @@ -691,7 +691,7 @@ represent across-year standard devations and the 1D array dimension represents different variables, see `averageClimateAcrossYears()`. */ typedef struct { - RealD *meanTempMon_C, /**< Array of size MAX_MONTHS containing sum of + double *meanTempMon_C, /**< Array of size MAX_MONTHS containing sum of monthly mean temperatures [C]*/ *maxTempMon_C, /**< Array of size MAX_MONTHS containing sum of monthly maximum temperatures [C]*/ @@ -731,14 +731,14 @@ typedef struct { } SW_CLIMATE_CLIM; typedef struct { - RealD **meanMonthlyTemp_C, **maxMonthlyTemp_C, **minMonthlyTemp_C, + double **meanMonthlyTemp_C, **maxMonthlyTemp_C, **minMonthlyTemp_C, **monthlyPPT_cm, *annualPPT_cm, *meanAnnualTemp_C, *JulyMinTemp, *frostFreeDays_days, *ddAbove65F_degday, *JulyPPT_mm, *meanTempDriestQuarter_C, *minTempFebruary_C; } SW_CLIMATE_CALC; typedef struct { - RealD *meanMonthlyTempAnn, *maxMonthlyTempAnn, *minMonthlyTempAnn, + double *meanMonthlyTempAnn, *maxMonthlyTempAnn, *minMonthlyTempAnn, *meanMonthlyPPTAnn, *sdC4, *sdCheatgrass, MAT_C, MAP_cm, JulyPPTAnn_mm, meanTempDriestQuarterAnn_C, minTempFebruaryAnn_C, ddAbove65F_degdayAnn, frostFreeAnn, JulyMinTempAnn; @@ -757,16 +757,16 @@ typedef struct { int rng_seed; // initial state for `mark - RealD pct_snowdrift, pct_snowRunoff; - RealD scale_precip[MAX_MONTHS], scale_temp_max[MAX_MONTHS], + double pct_snowdrift, pct_snowRunoff; + double scale_precip[MAX_MONTHS], scale_temp_max[MAX_MONTHS], scale_temp_min[MAX_MONTHS], scale_skyCover[MAX_MONTHS], scale_wind[MAX_MONTHS], scale_rH[MAX_MONTHS], scale_actVapPress[MAX_MONTHS], scale_shortWaveRad[MAX_MONTHS]; char name_prefix[MAX_FILENAMESIZE - 5]; // subtract 4-digit 'year' file type // extension - RealD snowRunoff, surfaceRunoff, surfaceRunon, soil_inf, surfaceAvg; - RealD snow, snowmelt, snowloss, surfaceMax, surfaceMin; - RealD temp_snow; // Snow temperature + double snowRunoff, surfaceRunoff, surfaceRunon, soil_inf, surfaceAvg; + double snow, snowmelt, snowloss, surfaceMax, surfaceMin; + double temp_snow; // Snow temperature Bool use_cloudCoverMonthly, use_windSpeedMonthly, use_humidityMonthly; Bool dailyInputFlags[MAX_INPUT_COLUMNS]; @@ -807,14 +807,14 @@ typedef struct { int method; /* method: 1=average; 2=hist+/- stderr */ SW_TIMES yr; char *file_prefix; /* prefix to historical swc filenames */ - RealD swc[MAX_DAYS][MAX_LAYERS], std_err[MAX_DAYS][MAX_LAYERS]; + double swc[MAX_DAYS][MAX_LAYERS], std_err[MAX_DAYS][MAX_LAYERS]; } SW_SOILWAT_HIST; /* accumulators for output values hold only the */ /* current period's values (eg, weekly or monthly) */ typedef struct { - RealD wetdays[MAX_LAYERS], + double wetdays[MAX_LAYERS], vwcBulk[MAX_LAYERS], /* soil water content cm/cm */ vwcMatric[MAX_LAYERS], swcBulk[MAX_LAYERS], /* soil water content cm/layer */ @@ -846,7 +846,7 @@ typedef struct { typedef struct { /* current daily soil water related values */ Bool is_wet[MAX_LAYERS]; /* swc sufficient to count as wet today */ - RealD swcBulk[TWO_DAYS][MAX_LAYERS], SWA_VegType[TWO_DAYS][MAX_LAYERS], + double swcBulk[TWO_DAYS][MAX_LAYERS], SWA_VegType[TWO_DAYS][MAX_LAYERS], snowpack[TWO_DAYS], /* swe of snowpack, if accumulation flag set */ snowdepth, transpiration[NVEGTYPES][MAX_LAYERS], evap_baresoil[MAX_LAYERS], /* bare-soil evaporation [cm/layer] */ @@ -864,15 +864,15 @@ typedef struct { maxLyrTemperature[MAX_LAYERS]; // Holds the maximum temperature // estimation of each layer - RealD veg_int_storage[NVEGTYPES], // storage of intercepted rain by the - // vegetation + double veg_int_storage[NVEGTYPES], // storage of intercepted rain by the + // vegetation litter_int_storage, // storage of intercepted rain by the litter layer standingWater[TWO_DAYS]; /* water on soil surface if layer below is saturated */ - RealF swa_master[NVEGTYPES][NVEGTYPES] - [MAX_LAYERS]; // veg_type, crit_val, layer - RealF dSWA_repartitioned_sum[NVEGTYPES][MAX_LAYERS]; + double swa_master[NVEGTYPES][NVEGTYPES] + [MAX_LAYERS]; // veg_type, crit_val, layer + double dSWA_repartitioned_sum[NVEGTYPES][MAX_LAYERS]; Bool soiltempError; // soil temperature error indicator #ifdef SWDEBUG @@ -916,7 +916,7 @@ typedef struct { typedef struct { char *InFiles[SW_NFILES]; - char _ProjDir[FILENAME_MAX]; + char SW_ProjDir[FILENAME_MAX]; // SW_ProjDir char weather_prefix[FILENAME_MAX]; char output_prefix[FILENAME_MAX]; } PATH_INFO; @@ -926,7 +926,7 @@ typedef struct { /* --------------------------------------------------- */ typedef struct { - RealD cloudcov[MAX_MONTHS], /* monthly cloud cover (frac) */ + double cloudcov[MAX_MONTHS], /* monthly cloud cover (frac) */ windspeed[MAX_MONTHS], /* windspeed (m/s) */ r_humidity[MAX_MONTHS], /* relative humidity (%) */ snow_density[MAX_MONTHS], /* snow density (kg/m3) */ @@ -934,7 +934,7 @@ typedef struct { (currently used in interception functions) */ - RealD snow_density_daily[MAX_DAYS + 1]; /* interpolated daily snow density + double snow_density_daily[MAX_DAYS + 1]; /* interpolated daily snow density (kg/m3) */ } SW_SKY; @@ -982,7 +982,7 @@ typedef struct { estab_lyrs; /* estab could conceivably need more than one layer */ /* swc is averaged over these top layers to compare to */ /* the converted value from min_swc_estab */ - RealF bars[2], /* read from input, saved for reporting */ + double bars[2], /* read from input, saved for reporting */ min_swc_germ, /* wetting point required for germination converted from */ /* bars to cm per layer for efficiency in the loop */ @@ -1023,14 +1023,14 @@ typedef struct { /* pointers to arrays of probabilities for each day saves some space */ /* by not being allocated if markov weather not requested by user */ /* alas, multi-dimensional arrays aren't so convenient */ - RealD *wetprob, /* probability of being wet today given a wet yesterday */ - *dryprob, /* probability of being wet today given a dry yesterday */ - *avg_ppt, /* mean precip (cm) of wet days */ - *std_ppt, /* std dev. for precip of wet days */ - *cfxw, /*correction factor for tmax for wet days */ - *cfxd, /*correction factor for tmax for dry days */ - *cfnw, /*correction factor for tmin for wet days */ - *cfnd, /*correction factor for tmin for dry days */ + double *wetprob, /* probability of being wet today given a wet yesterday */ + *dryprob, /* probability of being wet today given a dry yesterday */ + *avg_ppt, /* mean precip (cm) of wet days */ + *std_ppt, /* std dev. for precip of wet days */ + *cfxw, /*correction factor for tmax for wet days */ + *cfxd, /*correction factor for tmax for dry days */ + *cfnw, /*correction factor for tmin for wet days */ + *cfnd, /*correction factor for tmin for dry days */ u_cov[MAX_WEEKS][2], /* mean weekly maximum and minimum temperature in degree Celsius */ v_cov[MAX_WEEKS][2][2]; /* covariance matrix */ @@ -1341,13 +1341,13 @@ typedef struct { The variable p_OUT used by rSOILWAT2 for output, by STEPWAT2 for mean aggregation, and by SOILWAT2 when user requests netCDF output files. */ - RealD *p_OUT[SW_OUTNKEYS][SW_OUTNPERIODS]; + double *p_OUT[SW_OUTNKEYS][SW_OUTNPERIODS]; size_t irow_OUT[SW_OUTNPERIODS]; /**< current output time step index */ #endif #ifdef STEPWAT - RealD *p_OUTsd[SW_OUTNKEYS][SW_OUTNPERIODS]; + double *p_OUTsd[SW_OUTNKEYS][SW_OUTNPERIODS]; char sw_outstr_agg[MAX_LAYERS * OUTSTRLEN]; @@ -1357,22 +1357,22 @@ typedef struct { /* Variables from SXW_t (STEPWAT2) used in SOILWAT2 */ // transpXXX: monthly sum of soilwat's transpiration by soil layer // * these are dynamic arrays that are indexed by Ilp() - RealD transpTotal[MAX_LAYERS][MAX_MONTHS], // total transpiration, i.e., sum - // across vegetation types + double transpTotal[MAX_LAYERS][MAX_MONTHS], // total transpiration, i.e., + // sum across vegetation types transpVeg[NVEGTYPES][MAX_LAYERS] [MAX_MONTHS]; // transpiration as contributed by vegetation // types - RealF swc[MAX_LAYERS] - [MAX_MONTHS]; // monthly mean SWCbulk for each soil layer + double swc[MAX_LAYERS] + [MAX_MONTHS]; // monthly mean SWCbulk for each soil layer // fixed monthly array: - RealF ppt_monthly[MAX_MONTHS]; // monthly sum of soilwat's precipitation - RealF temp_monthly[MAX_MONTHS]; // monthly mean soilwat's air temperature + double ppt_monthly[MAX_MONTHS]; // monthly sum of soilwat's precipitation + double temp_monthly[MAX_MONTHS]; // monthly mean soilwat's air temperature // annual values: - RealF temp, // annual mean soilwat's air temperature - ppt, // annual sum of soilwat's precipitation - aet; // annual sum of soilwat's evapotranspiration + double temp, // annual mean soilwat's air temperature + ppt, // annual sum of soilwat's precipitation + aet; // annual sum of soilwat's evapotranspiration #endif } SW_OUT_RUN; diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index 67758feaf..a09f5ba07 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -48,10 +48,10 @@ extern "C" { /* --------------------------------------------------- */ void SW_NC_write_output( SW_OUT_DOM *OutDom, - RealD *p_OUT[][SW_OUTNPERIODS], - int numFilesPerKey, + double *p_OUT[][SW_OUTNPERIODS], + unsigned int numFilesPerKey, char **ncOutFileNames[][SW_OUTNPERIODS], - size_t ncSuid[], + const size_t ncSuid[], const char *domType, LOG_INFO *LogInfo ); @@ -69,10 +69,10 @@ void SW_NC_create_output_files( Bool hasConsistentSoilLayerDepths, double lyrDepths[], int strideOutYears, - int startYr, - int endYr, + unsigned int startYr, + unsigned int endYr, int baseCalendarYear, - int *numFilesPerKey, + unsigned int *numFilesPerKey, char **ncOutFileNames[][SW_OUTNPERIODS], LOG_INFO *LogInfo ); @@ -156,7 +156,9 @@ void SW_NC_alloc_outputkey_var_info( SW_OUT_DOM *OutDom, int key, LOG_INFO *LogInfo ); -void SW_NC_alloc_files(char ***ncOutFiles, int numFiles, LOG_INFO *LogInfo); +void SW_NC_alloc_files( + char ***ncOutFiles, unsigned int numFiles, LOG_INFO *LogInfo +); #ifdef __cplusplus } diff --git a/include/Times.h b/include/Times.h index ff0da02d2..858df139a 100644 --- a/include/Times.h +++ b/include/Times.h @@ -87,10 +87,10 @@ TimeInt Time_days_in_month(TimeInt month, TimeInt days_in_month[]); TimeInt Time_get_lastdoy_y(TimeInt year); -TimeInt doy2month(const TimeInt doy, TimeInt cum_monthdays[]); +TimeInt doy2month(const TimeInt doy, const TimeInt cum_monthdays[]); TimeInt doy2mday( - const TimeInt doy, TimeInt cum_monthdays[], TimeInt days_in_month[] + const TimeInt doy, TimeInt cum_monthdays[], const TimeInt days_in_month[] ); TimeInt doy2week(TimeInt doy); @@ -100,7 +100,7 @@ TimeInt yearto4digit(TimeInt yr); Bool isleapyear(const TimeInt year); void interpolate_monthlyValues( - double monthlyValues[], + const double monthlyValues[], Bool interpAsBase1, TimeInt cum_monthdays[], TimeInt days_in_month[], diff --git a/include/filefuncs.h b/include/filefuncs.h index c20895ac4..ebfa32899 100644 --- a/include/filefuncs.h +++ b/include/filefuncs.h @@ -31,13 +31,13 @@ void DirName(const char *p, char *outString); const char *BaseName(const char *p); -Bool FileExists(const char *f); +Bool FileExists(const char *name); Bool DirExists(const char *d); Bool ChDir(const char *d); -Bool MkDir(const char *dname, LOG_INFO *LogInfo); +void MkDir(const char *dname, LOG_INFO *LogInfo); Bool RemoveFiles(const char *fspec, LOG_INFO *LogInfo); @@ -47,6 +47,17 @@ void LogError(LOG_INFO *LogInfo, const int mode, const char *fmt, ...); void sw_message(const char *msg); +unsigned long int sw_strtoul( + const char *str, const char *errMsg, LOG_INFO *LogInfo +); + +long int sw_strtol(const char *str, const char *errMsg, LOG_INFO *LogInfo); + +int sw_strtoi(const char *str, const char *errMsg, LOG_INFO *LogInfo); + +double sw_strtod(const char *str, const char *errMsg, LOG_INFO *LogInfo); + +float sw_strtof(const char *str, const char *errMsg, LOG_INFO *LogInfo); int key_to_id(const char *key, const char **possibleKeys, int numPossKeys); @@ -55,7 +66,7 @@ void set_hasKey( ); void check_requiredKeys( - Bool *hasKeys, + const Bool *hasKeys, const Bool *requiredKeys, const char **possibleKeys, int numKeys, diff --git a/include/generic.h b/include/generic.h index 37fabd265..dd41840a4 100644 --- a/include/generic.h +++ b/include/generic.h @@ -61,8 +61,9 @@ #ifndef GENERIC_H #define GENERIC_H -#include // for FLT_EPSILON, DBL_EPSILON -#include // for fabs, sqrt, sqrtf, fmax, fmin +#include // for DBL_EPSILON, FLT_EPSILON +#include // for fabs, sqrt, sqrtf +#include // for NULL #ifdef RSOILWAT #include // for Rprintf() from @@ -99,18 +100,9 @@ extern "C" { #define fmin(a, b) ((LT((a), (b))) ? (a) : (b)) #endif -/* redefine sqrt for double (default) or float */ -#ifdef NO_SQRTF /* the case for Borland's compiler */ -#define sqrtf sqrt -#endif - -#define sqrt(x) ((sizeof(x) == sizeof(float)) ? sqrtf(x) : sqrt(x)) - #define isnull(a) (NULL == (a)) /* --------- Redefine basic types to be more malleable ---- */ -typedef float RealF; -typedef double RealD; typedef int Int; typedef unsigned int IntU; typedef short int IntS; @@ -122,16 +114,6 @@ typedef enum { swFALSE = (1 != 1), swTRUE = (1 == 1) } Bool; typedef unsigned char byte; -/* an attempt to facilitate integer implementation of real */ -/* - typedef long IRealF - typedef double long IRealD - #define IF_GRAIN 10000000L - #define F2I(x) ((IRealF)(x*IF_GRAIN)) - #define D2I(x) ((IRealD)(x*ID_GRAIN)) - #define I2F(x) ((( RealF)x/IF_GRAIN)) - #define I2D(x) ((( RealD)x/ID_GRAIN)) - */ /* --------------------------------------------------*/ /* These are facilities for logging errors. */ @@ -153,6 +135,7 @@ typedef unsigned char byte; /* --------------------------------------------------*/ /* --------------------------------------------------*/ + /* The following tests account for imprecision in the floating point representation of either single or double real numbers. Use these instead of @@ -200,10 +183,16 @@ typedef unsigned char byte; for floats/doubles, which are typically not used with side-effecting expressions. */ -#define F_DELTA (10 * FLT_EPSILON) #define D_DELTA (10 * DBL_EPSILON) +#if defined(STEPWAT) +/* ------ STEPWAT2 uses floats and doubles ------ */ +typedef float RealF; +typedef double RealD; + +#define F_DELTA (10 * FLT_EPSILON) + // new definitions for these four macros (MUCH MUCH faster, by a factor of about // 4)... just trying them out for now. The idea behind how these work is that // both an absolute error and relative error check are being used in conjunction @@ -215,13 +204,6 @@ typedef unsigned char byte; (MAX(F_DELTA, FLT_EPSILON * MAX(fabs(x), fabs(y)))) : \ (MAX(D_DELTA, DBL_EPSILON * MAX(fabs(x), fabs(y))))) -/**< LT tests whether x is less than y while accounting for floating-point - * arithmetic */ -#define LT(x, y) ((x) < ((y) - GET_F_DELTA(x, y))) - -/**< GT tests whether x is greater than y while accounting for floating-point - * arithmetic */ -#define GT(x, y) ((x) > ((y) + GET_F_DELTA(x, y))) /**< ZRO tests whether x is equal to zero while accounting for floating-point * arithmetic */ @@ -231,6 +213,45 @@ typedef unsigned char byte; #define ZRO(x) \ ((sizeof(x) == sizeof(float)) ? (fabs(x) <= F_DELTA) : (fabs(x) <= D_DELTA)) + +/* redefine sqrt for double (default) or float */ +#ifdef NO_SQRTF /* the case for Borland's compiler */ +#define sqrtf sqrt +#endif + +#define sqrt(x) ((sizeof(x) == sizeof(float)) ? sqrtf(x) : sqrt(x)) + + +#else /* !defined(STEPWAT), i.e., SOILWAT2 and rSOILWAT2 */ +/* ------ SOILWAT2 uses doubles (>= v8.1.0) ------ */ + +// new definitions for these four macros (MUCH MUCH faster, by a factor of about +// 4)... just trying them out for now. The idea behind how these work is that +// both an absolute error and relative error check are being used in conjunction +// with one another. In this for now I'm using F_DELTA for the amount of +// absolute error allowed and FLT_EPSILON for the amount of relative error +// allowed. +#define GET_F_DELTA(x, y) (MAX(D_DELTA, DBL_EPSILON * MAX(fabs(x), fabs(y)))) + +/**< ZRO tests whether x is equal to zero while accounting for floating-point + * arithmetic */ +// for iszero(x) we just use an absolute error check, because a relative error +// check doesn't make sense for any number close enough to zero to be considered +// equal... it would be a waste of time. +#define ZRO(x) (fabs(x) <= D_DELTA) + +#endif + + +/**< LT tests whether x is less than y while accounting for floating-point + * arithmetic */ +#define LT(x, y) ((x) < ((y) - GET_F_DELTA(x, y))) + +/**< GT tests whether x is greater than y while accounting for floating-point + * arithmetic */ +#define GT(x, y) ((x) > ((y) + GET_F_DELTA(x, y))) + + /**< EQ tests whether x and y are equal based on a specified tolerance */ #define EQ_w_tol(x, y, tol) (fabs((x) - (y)) <= tol) @@ -279,7 +300,7 @@ char *Str_ToLower(char *s, char *r); int Str_CompareI(char *t, char *s); char *sw_strtok( - char inputStr[], int *startIndex, int *strLen, const char *delim + char inputStr[], size_t *startIndex, size_t *strLen, const char *delim ); Bool isDelim(char currChar, const char *delim); @@ -297,11 +318,11 @@ void st_getBounds( double bounds[] ); -double lobfM(double xs[], double ys[], unsigned int n); +double lobfM(const double xs[], const double ys[], unsigned int n); double lobfB(double xs[], double ys[], unsigned int n); -void lobf(double *m, double *b, double xs[], double ys[], unsigned int size); +void lobf(double *m, double *b, double xs[], double ys[], unsigned int n); double get_running_mean(unsigned int n, double mean_prev, double val_to_add); @@ -312,9 +333,9 @@ double get_running_sqr( double final_running_sd(unsigned int n, double ssqr); -double mean(double values[], int length); +double mean(const double values[], unsigned int length); -double standardDeviation(double inputArray[], int length); +double standardDeviation(double inputArray[], unsigned int length); #ifdef __cplusplus diff --git a/include/myMemory.h b/include/myMemory.h index cae71c573..6c1d794b5 100644 --- a/include/myMemory.h +++ b/include/myMemory.h @@ -31,6 +31,9 @@ void Mem_Set(void *block, byte c, size_t n); void Mem_Copy(void *dest, const void *src, size_t n); +void *sw_memccpy_custom( + void *__restrict dest, void *__restrict src, int c, size_t n +); #ifdef __cplusplus } diff --git a/include/rands.h b/include/rands.h index 38868e17f..2c3c47767 100644 --- a/include/rands.h +++ b/include/rands.h @@ -33,7 +33,7 @@ void RandSeed( double RandUni(sw_random_t *pcg_rng); -int RandUniIntRange(const long first, const long last, sw_random_t *pcg_rng); +long RandUniIntRange(const long first, const long last, sw_random_t *pcg_rng); float RandUniFloatRange(const float min, const float max, sw_random_t *pcg_rng); @@ -48,7 +48,7 @@ void RandUniList( LOG_INFO *LogInfo ); -float RandBeta(float aa, float bb, sw_random_t *pcg_rng, LOG_INFO *LogInfo); +double RandBeta(double aa, double bb, sw_random_t *pcg_rng, LOG_INFO *LogInfo); #ifdef __cplusplus diff --git a/makefile b/makefile index d021c7c66..6b6abc89e 100644 --- a/makefile +++ b/makefile @@ -521,6 +521,14 @@ cov : ./tools/run_gcov.sh +#--- Targets for clang-tidy +tidy-bin: $(sources_lib) $(sources_bin) + clang-tidy --config-file=.clang-tidy $(sources_lib) $(sources_bin) -- $(sw_CPPFLAGS_bin) $(sw_CFLAGS) $(bin_flags) $(warning_flags) $(set_std) + +tidy-test: $(sources_test) + clang-tidy --config-file=.clang-tidy_swtest $(sources_test) -- $(sw_CPPFLAGS_test) $(sw_CXXFLAGS) $(gtest_flags) $(debug_flags) $(warning_flags) $(instr_flags) $(set_std++_tests) -isystem ${dir_gmock}/include -isystem ${dir_gtest}/include + + #--- Convenience targets for documentation .PHONY : doc doc : diff --git a/src/SW_Carbon.c b/src/SW_Carbon.c index 81592c1d4..654805079 100644 --- a/src/SW_Carbon.c +++ b/src/SW_Carbon.c @@ -84,7 +84,10 @@ void SW_CBN_read( /* Reading carbon.in */ FILE *f; char scenario[64]; + char yearStr[5]; + char ppmStr[20]; int year; + int scanRes; int simstartyr = (int) SW_Model->startyr + SW_Model->addtl_yr; int simendyr = (int) SW_Model->endyr + SW_Model->addtl_yr; @@ -93,7 +96,8 @@ void SW_CBN_read( double ppm = 1.; int existing_years[MAX_NYEAR] = {0}; short fileWasEmpty = 1; - char *MyFileName, inbuf[MAX_FILENAMESIZE]; + char *MyFileName; + char inbuf[MAX_FILENAMESIZE]; MyFileName = InFiles[eCarbon]; f = OpenFile(MyFileName, "r", LogInfo); @@ -121,11 +125,46 @@ void SW_CBN_read( // Read the year standalone because if it's 0 it marks a change in the // scenario, in which case we'll need to read in a string instead of an // int - sscanf(inbuf, "%d", &year); + scanRes = sscanf(inbuf, "%4s", yearStr); + + if (scanRes < 1) { + LogError( + LogInfo, + LOGERROR, + "Not enough values when reading in the year from %s.", + MyFileName + ); + goto closeFile; + } + + year = sw_strtoi(yearStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } // Find scenario if (year == 0) { - sscanf(inbuf, "%d %63s", &year, scenario); + scanRes = sscanf(inbuf, "%4s %63s", yearStr, scenario); + + if (scanRes < 2) { + LogError( + LogInfo, + LOGERROR, + "Not enough values when reading in the year and " + "scenario from %s.", + MyFileName + ); + goto closeFile; + } + + year = sw_strtoi(yearStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + + /* Silence clang-tidy clang-analyzer-deadcode.DeadStores */ + (void) year; + continue; // Skip to the ppm values } if (strcmp(scenario, SW_Carbon->scenario) != 0) { @@ -135,10 +174,30 @@ void SW_CBN_read( continue; // We aren't using this year } - sscanf(inbuf, "%d %lf", &year, &ppm); + scanRes = sscanf(inbuf, "%4s %19s", yearStr, ppmStr); + + if (scanRes < 2) { + LogError( + LogInfo, + LOGERROR, + "Not enough values when reading in the year and " + "ppm from %s.", + MyFileName + ); + goto closeFile; + } + + year = sw_strtoi(yearStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + + ppm = sw_strtod(ppmStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } if (year < 0) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -148,7 +207,7 @@ void SW_CBN_read( year, SW_Carbon->scenario ); - return; // Exit function prematurely due to error + goto closeFile; } SW_Carbon->ppm[year] = ppm; @@ -168,7 +227,6 @@ void SW_CBN_read( 1][year].grass != 1.0, due to floating point precision and the chance that a multiplier of 1.0 was actually calculated */ if (existing_years[year] != 0) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -178,14 +236,11 @@ void SW_CBN_read( year, SW_Carbon->scenario ); - return; // Exit function prematurely due to error + goto closeFile; } existing_years[year] = 1; } - CloseFile(&f, LogInfo); - - /* Error checking */ // Must check if the file was empty before checking if the scneario was @@ -199,7 +254,7 @@ void SW_CBN_read( " debugging purposes, SOILWAT2 read in file '%s'\n", MyFileName ); - return; // Exit function prematurely due to error + goto closeFile; } // A scenario must be found in order for ppm to have a positive value @@ -211,7 +266,7 @@ void SW_CBN_read( " was not found in carbon.in\n", SW_Carbon->scenario ); - return; // Exit function prematurely due to error + goto closeFile; } // Ensure that the desired years were calculated @@ -226,9 +281,11 @@ void SW_CBN_read( year, SW_Carbon->scenario ); - return; // Exit function prematurely due to error + goto closeFile; } } + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -255,13 +312,15 @@ void SW_CBN_init_run( SW_CARBON *SW_Carbon, LOG_INFO *LogInfo ) { - int k; - TimeInt year, simendyr = SW_Model->endyr + SW_Model->addtl_yr; - double ppm; #ifdef SWDEBUG short debug = 0; #endif + int k; + TimeInt year; + TimeInt simendyr = SW_Model->endyr + SW_Model->addtl_yr; + double ppm; + if (!SW_Carbon->use_bio_mult && !SW_Carbon->use_wue_mult) { return; } diff --git a/src/SW_Control.c b/src/SW_Control.c index b3affe216..690b3f222 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -76,7 +76,7 @@ information that do not change throughout simulation runs @param[out] LogInfo Holds information on warnings and errors */ -static void _begin_year(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { +static void begin_year(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { // SW_F_new_year() not needed // call SW_MDL_new_year() first to set up time-related arrays for this year @@ -113,7 +113,7 @@ static void _begin_year(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { ); } -static void _begin_day(SW_RUN *sw, LOG_INFO *LogInfo) { +static void begin_day(SW_RUN *sw, LOG_INFO *LogInfo) { SW_MDL_new_day(&sw->Model); SW_WTH_new_day( &sw->Weather, @@ -125,11 +125,11 @@ static void _begin_day(SW_RUN *sw, LOG_INFO *LogInfo) { ); } -static void _end_day(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { +static void end_day(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { int localTOffset = 1; // tOffset is one when called from this function if (sw->Model.doOutput) { - _collect_values(sw, OutDom, swFALSE, localTOffset, LogInfo); + collect_values(sw, OutDom, swFALSE, localTOffset, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -197,7 +197,7 @@ void SW_RUN_deepCopy( for (IntU speciesNum = 0; speciesNum < source->VegEstab.count; speciesNum++) { - _new_species(&dest->VegEstab, LogInfo); + new_species(&dest->VegEstab, LogInfo); if (LogInfo->stopRun) { return; // Exit prematurely due to error } @@ -269,15 +269,19 @@ void SW_CTL_RunSimSet( LOG_INFO *main_LogInfo ) { - unsigned long suid, nSims = 0; + unsigned long suid; + unsigned long nSims = 0; unsigned long ncSuid[2]; // 2 -> [y, x] or [s, 0] /* tag_suid is 32: 11 character for "(suid = ) " + 20 character for ULONG_MAX + '\0' */ char tag_suid[32]; tag_suid[0] = '\0'; - WallTimeSpec tss, tsr; - Bool ok_tss = swFALSE, ok_tsr = swFALSE, ok_suid; + WallTimeSpec tss; + WallTimeSpec tsr; + Bool ok_tss = swFALSE; + Bool ok_tsr = swFALSE; + Bool ok_suid; int progFileID = 0; // Value does not matter if SWNETCDF is not defined int progVarID = 0; // Value does not matter if SWNETCDF is not defined @@ -347,7 +351,7 @@ void SW_CTL_RunSimSet( } if (local_LogInfo.stopRun || local_LogInfo.numWarnings > 0) { - snprintf(tag_suid, 32, "(suid = %lu) ", suid + 1); + (void) snprintf(tag_suid, 32, "(suid = %lu) ", suid + 1); sw_write_warnings(tag_suid, &local_LogInfo); } } @@ -416,7 +420,7 @@ void SW_CTL_setup_domain( SW_F_construct( SW_Domain->PathInfo.InFiles[eFirst], - SW_Domain->PathInfo._ProjDir, + SW_Domain->PathInfo.SW_ProjDir, LogInfo ); if (LogInfo->stopRun) { @@ -520,13 +524,7 @@ void SW_CTL_setup_model( SW_VPD_construct(&sw->VegProd); // SW_FLW_construct() not needed SW_OUT_construct( - zeroOutInfo, - sw->FileStatus.make_soil, - sw->FileStatus.make_regular, - OutDom, - &sw->OutRun, - sw->Site.n_layers, - LogInfo + zeroOutInfo, &sw->FileStatus, OutDom, &sw->OutRun, LogInfo ); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -567,7 +565,7 @@ void SW_CTL_clear_model(Bool full_reset, SW_RUN *sw) { @brief Initialize simulation run (based on user inputs) Note: Time will only be set up correctly while carrying out a simulation year, -i.e., after calling _begin_year() +i.e., after calling begin_year() @param[in,out] sw Comprehensive structure holding all information dealt with in SOILWAT2 @@ -624,17 +622,19 @@ void SW_CTL_run_current_year( SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo ) { /*=======================================================*/ - TimeInt *doy = &sw->Model.doy; // base1 #ifdef SWDEBUG int debug = 0; #endif + TimeInt *doy = &sw->Model.doy; // base1 + #ifdef SWDEBUG if (debug) { sw_printf("\n'SW_CTL_run_current_year': begin new year\n"); } #endif - _begin_year(sw, OutDom, LogInfo); + + begin_year(sw, OutDom, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -645,7 +645,7 @@ void SW_CTL_run_current_year( sw_printf("\t: begin doy = %d ... ", *doy); } #endif - _begin_day(sw, LogInfo); + begin_day(sw, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -686,7 +686,7 @@ void SW_CTL_run_current_year( sw_printf("ending day ... "); } #endif - _end_day(sw, OutDom, LogInfo); + end_day(sw, OutDom, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -743,9 +743,16 @@ void SW_CTL_run_spinup(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { return; } - unsigned int i, k, quotient = 0, remainder = 0; +#ifdef SWDEBUG + int debug = 0; +#endif + + unsigned int i; + unsigned int k; + unsigned int quotient = 0; + unsigned int remainder = 0; int mode = sw->Model.SW_SpinUp.mode; - int yr; + TimeInt yr; TimeInt duration = sw->Model.SW_SpinUp.duration; TimeInt scope = sw->Model.SW_SpinUp.scope; TimeInt finalyr = sw->Model.startyr + scope - 1; @@ -758,10 +765,6 @@ void SW_CTL_run_spinup(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { return; // Exit function prematurely due to error } -#ifdef SWDEBUG - int debug = 0; -#endif - #ifdef SWDEBUG if (debug) { sw_printf( @@ -812,7 +815,9 @@ void SW_CTL_run_spinup(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { break; } - TimeInt *cur_yr = &sw->Model.year, yrIdx, startyr = sw->Model.startyr; + TimeInt *cur_yr = &sw->Model.year; + TimeInt yrIdx; + TimeInt startyr = sw->Model.startyr; sw->Model.startyr = years[0]; // set startyr for spinup @@ -891,7 +896,6 @@ void SW_CTL_read_inputs_from_disk( sw_printf(" > 'weather setup'"); } #endif - SW_SKY_read(PathInfo->InFiles, &sw->Sky, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -970,7 +974,9 @@ void SW_CTL_read_inputs_from_disk( } #endif - SW_VES_read(&sw->VegEstab, PathInfo->InFiles, PathInfo->_ProjDir, LogInfo); + SW_VES_read( + &sw->VegEstab, PathInfo->InFiles, PathInfo->SW_ProjDir, LogInfo + ); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -1029,7 +1035,7 @@ on error but end early and report to caller void SW_CTL_run_sw( SW_RUN *sw_template, SW_DOMAIN *SW_Domain, - unsigned long ncSuid[], + unsigned long ncSuid[], // NOLINT(readability-non-const-parameter) LOG_INFO *LogInfo ) { diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 6d51bcbdc..b1c9230ce 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -5,15 +5,15 @@ #include "include/SW_Domain.h" // for SW_DOM_CheckProgress, SW_DOM_Cre... #include "include/filefuncs.h" // for LogError, CloseFile, key_to_id #include "include/generic.h" // for swTRUE, LOGERROR, swFALSE, Bool -#include "include/myMemory.h" // for Str_Dup +#include "include/myMemory.h" // for sw_memccpy_custom #include "include/SW_datastructs.h" // for SW_DOMAIN, LOG_INFO #include "include/SW_Defines.h" // for LyrIndex, LARGE_VALUE, TimeInt #include "include/SW_Files.h" // for SW_F_deconstruct, SW_F_deepCopy #include "include/SW_Output.h" // for ForEachOutKey #include "include/Times.h" // for yearto4digit, Time_get_lastdoy_y #include // for sscanf, FILE -#include // for atoi, atof -#include // for strcmp, memcpy, strcpy, memset +#include // for strtod, strtol +#include // for strcmp, memcpy, memset #if defined(SWNETCDF) #include "include/SW_netCDF.h" @@ -86,7 +86,10 @@ TRUE if simulation for \p ncSuid has not been completed yet; FALSE if simulation for \p ncSuid has been completed (i.e., skip). */ Bool SW_DOM_CheckProgress( - int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO *LogInfo + int progFileID, + int progVarID, + unsigned long ncSuid[], // NOLINT(readability-non-const-parameter) + LOG_INFO *LogInfo ) { #if defined(SWNETCDF) return SW_NC_check_progress(progFileID, progVarID, ncSuid, LogInfo); @@ -143,7 +146,7 @@ void SW_DOM_construct(unsigned long rng_seed, SW_DOMAIN *SW_Domain) { SW_Domain->hasConsistentSoilLayerDepths = swFALSE; memset( &SW_Domain->depthsAllSoilLayers, - 0., + 0, sizeof(&SW_Domain->depthsAllSoilLayers[0]) * MAX_LAYERS ); @@ -200,9 +203,17 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { Bool hasKeys[NUM_DOM_IN_KEYS] = {swFALSE}; FILE *f; - int y, keyID; - char inbuf[LARGE_VALUE], *MyFileName; - char key[15], value[LARGE_VALUE]; // 15 - Max key size + int y; + int keyID; + char inbuf[LARGE_VALUE]; + char *MyFileName; + char key[15]; + char value[LARGE_VALUE]; // 15 - Max key size + int intRes = 0; + int scanRes; + double doubleRes = 0.; + + Bool doDoubleConv; MyFileName = SW_Domain->PathInfo.InFiles[eDomain]; f = OpenFile(MyFileName, "r", LogInfo); @@ -212,13 +223,39 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { // Set SW_DOMAIN while (GetALine(f, inbuf, LARGE_VALUE)) { - sscanf(inbuf, "%14s %s", key, value); + scanRes = sscanf(inbuf, "%14s %s", key, value); + + if (scanRes < 2) { + LogError( + LogInfo, LOGERROR, "Invalid key-value pair in %s.", MyFileName + ); + goto closeFile; + } keyID = key_to_id(key, possibleKeys, NUM_DOM_IN_KEYS); set_hasKey(keyID, possibleKeys, hasKeys, LogInfo); // set_hasKey() produces never an error, only possibly warnings + /* Make sure we are not trying to convert a string with no numerical + * value */ + if (keyID > 0 && keyID <= 16 && keyID != 8) { + + /* Check to see if the line number contains a double or integer + * value */ + doDoubleConv = (Bool) (keyID >= 9 && keyID <= 12); + + if (doDoubleConv) { + doubleRes = sw_strtod(value, MyFileName, LogInfo); + } else { + intRes = sw_strtoi(value, MyFileName, LogInfo); + } + + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (keyID) { case 0: // Domain type if (strcmp(value, "xy") != 0 && strcmp(value, "s") != 0) { @@ -230,25 +267,26 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { MyFileName, value ); - return; // Exit function prematurely due to error + goto closeFile; } - strcpy(SW_Domain->DomainType, value); + (void) sw_memccpy( + SW_Domain->DomainType, value, '\0', sizeof SW_Domain->DomainType + ); break; case 1: // Number of X slots - SW_Domain->nDimX = atoi(value); + SW_Domain->nDimX = intRes; break; case 2: // Number of Y slots - SW_Domain->nDimY = atoi(value); + SW_Domain->nDimY = intRes; break; case 3: // Number of S slots - SW_Domain->nDimS = atoi(value); + SW_Domain->nDimS = intRes; break; case 4: // Start year - y = atoi(value); + y = intRes; if (y < 0) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -256,15 +294,14 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { MyFileName, y ); - return; // Exit function prematurely due to error + goto closeFile; } SW_Domain->startyr = yearto4digit((TimeInt) y); break; case 5: // End year - y = atoi(value); + y = intRes; if (y < 0) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -272,40 +309,52 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { MyFileName, y ); - return; // Exit function prematurely due to error + goto closeFile; } SW_Domain->endyr = yearto4digit((TimeInt) y); break; case 6: // Start day of year - SW_Domain->startstart = atoi(value); + SW_Domain->startstart = intRes; break; case 7: // End day of year - SW_Domain->endend = atoi(value); + SW_Domain->endend = intRes; break; case 8: // CRS box // Re-scan and get the entire value (including spaces) - sscanf(inbuf, "%9s %27[^\n]", key, value); - strcpy(SW_Domain->crs_bbox, value); + scanRes = sscanf(inbuf, "%9s %27[^\n]", key, value); + + if (scanRes < 2) { + LogError( + LogInfo, + LOGERROR, + "Invalid key-value pair for CRS box in %s.", + MyFileName + ); + goto closeFile; + } + + (void) sw_memccpy( + SW_Domain->crs_bbox, value, '\0', sizeof SW_Domain->crs_bbox + ); break; case 9: // Minimum x coordinate - SW_Domain->min_x = atof(value); + SW_Domain->min_x = doubleRes; break; case 10: // Minimum y coordinate - SW_Domain->min_y = atof(value); + SW_Domain->min_y = doubleRes; break; case 11: // Maximum x coordinate - SW_Domain->max_x = atof(value); + SW_Domain->max_x = doubleRes; break; case 12: // Maximum y coordinate - SW_Domain->max_y = atof(value); + SW_Domain->max_y = doubleRes; break; case 13: // Spinup Mode - y = atoi(value); + y = intRes; if (y != 1 && y != 2) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -314,15 +363,15 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { MyFileName, y ); - return; // Exit function prematurely due to error + goto closeFile; } SW_Domain->SW_SpinUp.mode = y; break; case 14: // Spinup Scope - SW_Domain->SW_SpinUp.scope = atoi(value); + SW_Domain->SW_SpinUp.scope = intRes; break; case 15: // Spinup Duration - SW_Domain->SW_SpinUp.duration = atoi(value); + SW_Domain->SW_SpinUp.duration = intRes; // Set the spinup flag to true if duration > 0 if (SW_Domain->SW_SpinUp.duration <= 0) { @@ -332,10 +381,12 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { } break; case 16: // Spinup Seed - SW_Domain->SW_SpinUp.rng_seed = atoi(value); + SW_Domain->SW_SpinUp.rng_seed = intRes; break; case KEY_NOT_FOUND: // Unknown key + + default: LogError( LogInfo, LOGWARN, @@ -347,20 +398,18 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { } } - CloseFile(&f, LogInfo); - // Check if all required input was provided check_requiredKeys( hasKeys, requiredKeys, possibleKeys, NUM_DOM_IN_KEYS, LogInfo ); if (LogInfo->stopRun) { - return; // Exit function prematurely due to error + goto closeFile; } if (SW_Domain->endyr < SW_Domain->startyr) { LogError(LogInfo, LOGERROR, "%s: Start Year > End Year", MyFileName); - return; // Exit function prematurely due to error + goto closeFile; } // Check if start day of year was not found @@ -389,12 +438,12 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { // Check bounding box coordinates if (GT(SW_Domain->min_x, SW_Domain->max_x)) { LogError(LogInfo, LOGERROR, "Domain.in: bbox x-axis min > max."); - return; // Exit function prematurely due to error + goto closeFile; } if (GT(SW_Domain->min_y, SW_Domain->max_y)) { LogError(LogInfo, LOGERROR, "Domain.in: bbox y-axis min > max."); - return; // Exit function prematurely due to error + goto closeFile; } // Check if scope value is out of range @@ -407,8 +456,9 @@ void SW_DOM_read(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { MyFileName, SW_Domain->SW_SpinUp.scope ); - return; // Exit function prematurely due to error } + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -428,7 +478,7 @@ void SW_DOM_SetProgress( const char *domType, int progFileID, int progVarID, - unsigned long ncSuid[], + unsigned long ncSuid[], // NOLINT(readability-non-const-parameter) LOG_INFO *LogInfo ) { @@ -460,9 +510,9 @@ void SW_DOM_SimSet( ) { Bool progFound; - unsigned long *startSimSet = &SW_Domain->startSimSet, - *endSimSet = &SW_Domain->endSimSet, - startSuid[2]; // 2 -> [y, x] or [0, s] + unsigned long *startSimSet = &SW_Domain->startSimSet; + unsigned long *endSimSet = &SW_Domain->endSimSet; + unsigned long startSuid[2]; // 2 -> [y, x] or [0, s] int progFileID = 0; // Value does not matter if SWNETCDF is not defined int progVarID = 0; // Value does not matter if SWNETCDF is not defined @@ -538,7 +588,8 @@ void SW_DOM_init_ptrs(SW_DOMAIN *SW_Domain) { } void SW_DOM_deconstruct(SW_DOMAIN *SW_Domain) { - IntUS k, i; + int k; + int i; SW_F_deconstruct(SW_Domain->PathInfo.InFiles); diff --git a/src/SW_Files.c b/src/SW_Files.c index 084cfa83f..10f1b2895 100644 --- a/src/SW_Files.c +++ b/src/SW_Files.c @@ -39,7 +39,7 @@ #include "include/SW_Defines.h" // for MAX_FILENAMESIZE #include // for FILENAME_MAX, NULL, FILE, stderr #include // for free -#include // for strcpy, strcmp, strlen, memcpy +#include // for memccpy, strcmp, strlen, memcpy /* =================================================== */ /* Global Function Definitions */ @@ -60,24 +60,20 @@ void SW_CSV_F_INIT(const char *s, LOG_INFO *LogInfo) { * remove old output and/or create the output directories if needed */ /* borrow inbuf for filenames */ - char inbuf[MAX_FILENAMESIZE], dirString[FILENAME_MAX]; + char inbuf[MAX_FILENAMESIZE]; + char dirString[FILENAME_MAX]; DirName(s, dirString); if (DirExists(dirString)) { - strcpy(inbuf, s); + (void) sw_memccpy(inbuf, (char *) s, '\0', sizeof inbuf); if (!RemoveFiles(inbuf, LogInfo)) { LogError( LogInfo, LOGWARN, "Can't remove old csv output file: %s\n", s ); } - } else if (!MkDir(dirString, LogInfo)) { - LogError( - LogInfo, - LOGERROR, - "Can't make output path for csv file: %s\n", - dirString - ); + } else { + MkDir(dirString, LogInfo); } } @@ -101,13 +97,17 @@ Update values of variables within PATH_INFO: - `logfp` for SOILWAT2-standalone */ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { - FILE *f; - int lineno = 0, fileno = 0; - char buf[FILENAME_MAX], inbuf[MAX_FILENAMESIZE]; #ifdef SWDEBUG int debug = 0; #endif + FILE *f; + int lineno = 0; + int fileno = 0; + int resSNP; + char buf[FILENAME_MAX]; + char inbuf[MAX_FILENAMESIZE]; + char *MyFileName = PathInfo->InFiles[eFirst]; f = OpenFile(MyFileName, "r", LogInfo); if (LogInfo->stopRun) { @@ -126,16 +126,45 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { switch (lineno) { case 10: - strcpy(PathInfo->weather_prefix, inbuf); + resSNP = snprintf( + PathInfo->weather_prefix, + sizeof PathInfo->weather_prefix, + "%s", + inbuf + ); + if (resSNP < 0 || + (unsigned) resSNP >= (sizeof PathInfo->weather_prefix)) { + LogError( + LogInfo, + LOGERROR, + "weather prefix is too long: '%s'.", + inbuf + ); + goto closeFile; + } break; case 18: - strcpy(PathInfo->output_prefix, inbuf); + resSNP = snprintf( + PathInfo->output_prefix, + sizeof PathInfo->output_prefix, + "%s", + inbuf + ); + if (resSNP < 0 || + (unsigned) resSNP >= (sizeof PathInfo->output_prefix)) { + LogError( + LogInfo, + LOGERROR, + "output path name is too long: '%s'.", + inbuf + ); + goto closeFile; + } break; case 20: PathInfo->InFiles[eOutputDaily] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputDaily], LogInfo); @@ -143,8 +172,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 21: PathInfo->InFiles[eOutputWeekly] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputWeekly], LogInfo); @@ -153,8 +181,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 22: PathInfo->InFiles[eOutputMonthly] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputMonthly], LogInfo); @@ -163,8 +190,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 23: PathInfo->InFiles[eOutputYearly] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputYearly], LogInfo); @@ -172,8 +198,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 24: PathInfo->InFiles[eOutputDaily_soil] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputDaily_soil], LogInfo); @@ -182,8 +207,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 25: PathInfo->InFiles[eOutputWeekly_soil] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputWeekly_soil], LogInfo); @@ -192,8 +216,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 26: PathInfo->InFiles[eOutputMonthly_soil] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputMonthly_soil], LogInfo); @@ -202,8 +225,7 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { case 27: PathInfo->InFiles[eOutputYearly_soil] = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } ++fileno; SW_CSV_F_INIT(PathInfo->InFiles[eOutputYearly_soil], LogInfo); @@ -218,42 +240,40 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { free(PathInfo->InFiles[fileno]); } - strcpy(buf, PathInfo->_ProjDir); - strcat(buf, inbuf); + resSNP = + snprintf(buf, sizeof buf, "%s%s", PathInfo->SW_ProjDir, inbuf); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof buf)) { + LogError( + LogInfo, LOGERROR, "input file name is too long: '%s'.", buf + ); + goto closeFile; + } + PathInfo->InFiles[fileno] = Str_Dup(buf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } } // Check if something went wrong in `SW_CSV_F_INIT()` if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } lineno++; } - CloseFile(&f, LogInfo); - if (fileno < eEndFile - 1) { LogError( LogInfo, LOGERROR, "Too few files (%d) in %s", fileno, MyFileName ); - return; // Exit function prematurely due to error + goto closeFile; } if (!DirExists(PathInfo->output_prefix)) { - if (!MkDir(PathInfo->output_prefix, LogInfo)) { - LogError( - LogInfo, - LOGERROR, - "Cannot make output path: '%s'\n", - PathInfo->output_prefix - ); - return; // Exit function prematurely due to error + MkDir(PathInfo->output_prefix, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; } } @@ -266,6 +286,8 @@ void SW_F_read(PATH_INFO *PathInfo, LOG_INFO *LogInfo) { LogInfo->logfp = OpenFile(PathInfo->InFiles[eLog], "w", LogInfo); } #endif + +closeFile: { CloseFile(&f, LogInfo); } } void SW_F_deepCopy(PATH_INFO *source, PATH_INFO *dest, LOG_INFO *LogInfo) { @@ -299,40 +321,45 @@ void SW_F_init_ptrs(char *InFiles[]) { } /** -@brief Determines string length of file being read in combined with _ProjDir. +@brief Determines string length of file being read in combined with SW_ProjDir. @param[in] *firstfile File to be read in. -@param[out] _ProjDir Project directory +@param[out] SW_ProjDir Project directory @param[out] LogInfo Holds information on warnings and errors */ -void SW_F_construct(const char *firstfile, char _ProjDir[], LOG_INFO *LogInfo) { +void SW_F_construct( + const char *firstfile, char SW_ProjDir[], LOG_INFO *LogInfo +) { /* =================================================== */ /* 10-May-02 (cwb) enhancement allows model to be run * in one directory while getting its input from another. * This was done mostly in support of STEPWAT but * it could be useful in a standalone run. */ - char *c, *p, dirString[FILENAME_MAX]; - char *local_firstfile = Str_Dup(firstfile, LogInfo); + char *c; + char *p; + char dirString[FILENAME_MAX]; + char *localfirstfile = Str_Dup(firstfile, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } - DirName(local_firstfile, dirString); + DirName(localfirstfile, dirString); + c = dirString; - if ((c = dirString)) { - strcpy(_ProjDir, c); - c = local_firstfile; - p = c + strlen(_ProjDir); + if (c) { + (void) sw_memccpy(SW_ProjDir, c, '\0', sizeof dirString); + c = localfirstfile; + p = c + strlen(SW_ProjDir); while (*p) { *(c++) = *(p++); } *c = '\0'; } else { - _ProjDir[0] = '\0'; + SW_ProjDir[0] = '\0'; } - free(local_firstfile); + free(localfirstfile); } /** diff --git a/src/SW_Flow.c b/src/SW_Flow.c index 0a99bbdd6..ea87f435f 100644 --- a/src/SW_Flow.c +++ b/src/SW_Flow.c @@ -204,7 +204,7 @@ /* INCLUDES / DEFINES */ /* --------------------------------------------------- */ #include "include/SW_Flow.h" // for SW_FLW_init_run, SW_Water_Flow -#include "include/generic.h" // for RealD, GT, fmax, EQ, fmin +#include "include/generic.h" // for GT, fmax, EQ, fmin #include "include/SW_datastructs.h" // for LOG_INFO, SW_RUN, SW_SOILWAT #include "include/SW_Defines.h" // for ForEachVegType, NVEGTYPES, ForE... #include "include/SW_Flow_lib.h" // for evap_fromSurface, remove_from_soil @@ -232,7 +232,8 @@ void SW_FLW_init_run(SW_SOILWAT *SW_SoilWat) { /* 06/26/2013 (rjm) added function SW_FLW_init_run() to init global * variables between consecutive calls to SoilWat as dynamic library */ - int i, k; + int i; + int k; // These only have to be cleared if a loop is wrong in the code. @@ -261,24 +262,44 @@ void SW_FLW_init_run(SW_SOILWAT *SW_SoilWat) { /* --------------------------------------------------- */ void SW_Water_Flow(SW_RUN *sw, LOG_INFO *LogInfo) { #ifdef SWDEBUG - IntUS debug = 0, debug_year = 1980, debug_doy = 350; - double Eveg, Tveg, HRveg; + IntUS debug = 0; + IntUS debug_year = 1980; + IntUS debug_doy = 350; + double Eveg; + double Tveg; + double HRveg; #endif - RealD swpot_avg[NVEGTYPES], transp_veg[NVEGTYPES], transp_rate[NVEGTYPES], - soil_evap[NVEGTYPES], soil_evap_rate[NVEGTYPES], - soil_evap_rate_bs = 1., surface_evap_veg_rate[NVEGTYPES], - surface_evap_litter_rate = 1., surface_evap_standingWater_rate = 1., - h2o_for_soil = 0., snowmelt, scale_veg[NVEGTYPES], pet2, peti, - rate_help, x, drainout = 0; - RealD *standingWaterToday = &sw->SoilWat.standingWater[Today]; - RealD *standingWaterYesterday = &sw->SoilWat.standingWater[Yesterday]; - - int doy, month, k; - LyrIndex i, n_layers = sw->Site.n_layers; - - RealD UpNeigh_lyrSWCBulk[MAX_LAYERS], UpNeigh_lyrDrain[MAX_LAYERS]; - RealD UpNeigh_drainout, UpNeigh_standingWater; + double swpot_avg[NVEGTYPES]; + double transp_veg[NVEGTYPES]; + double transp_rate[NVEGTYPES]; + double soil_evap[NVEGTYPES]; + double soil_evap_rate[NVEGTYPES]; + double soil_evap_rate_bs = 1.; + double surface_evap_veg_rate[NVEGTYPES]; + double surface_evap_litter_rate = 1.; + double surface_evap_standingWater_rate = 1.; + double h2o_for_soil = 0.; + double snowmelt; + double scale_veg[NVEGTYPES]; + double pet2; + double peti; + double rate_help; + double x; + double drainout = 0; + double *standingWaterToday = &sw->SoilWat.standingWater[Today]; + double *standingWaterYesterday = &sw->SoilWat.standingWater[Yesterday]; + + TimeInt doy; + TimeInt month; + int k; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; + + double UpNeigh_lyrSWCBulk[MAX_LAYERS]; + double UpNeigh_lyrDrain[MAX_LAYERS]; + double UpNeigh_drainout; + double UpNeigh_standingWater; doy = sw->Model.doy; /* base1 */ month = sw->Model.month; /* base0 */ @@ -665,7 +686,6 @@ void SW_Water_Flow(SW_RUN *sw, LOG_INFO *LogInfo) { fmax(0., fmin(peti, sw->SoilWat.litter_int_storage)); peti -= surface_evap_litter_rate; surface_evap_standingWater_rate = fmax(0., fmin(peti, *standingWaterToday)); - peti -= surface_evap_standingWater_rate; /* Scale all (potential) evaporation and transpiration flux rates to (PET - * Esnow) */ diff --git a/src/SW_Flow_lib.c b/src/SW_Flow_lib.c index 8251cf621..8dd254bea 100644 --- a/src/SW_Flow_lib.c +++ b/src/SW_Flow_lib.c @@ -401,18 +401,19 @@ void infiltrate_water_high( double drain[], double *drainout, double pptleft, - int nlyrs, - double swcfc[], + unsigned int nlyrs, + const double swcfc[], double swcsat[], - double impermeability[], + const double impermeability[], double *standingWater, double lyrFrozen[] ) { - int i; - int j; + unsigned int i; + unsigned int j; double d[MAX_LAYERS] = {0}; - double push, ksat_rel; + double push; + double ksat_rel; // Infiltration swc[0] += pptleft + *standingWater; @@ -444,7 +445,9 @@ void infiltrate_water_high( /* adjust (i.e., push water upwards) if water content of a layer is now * above saturated water content */ - for (j = nlyrs - 1; j >= 0; j--) { + + /* reverse for-loop with j in [nlyrs - 1, 0] */ + for (j = nlyrs; j-- > 0;) { if (GT(swc[j], swcsat[j])) { push = swc[j] - swcsat[j]; swc[j] -= push; @@ -484,7 +487,7 @@ void transp_weighted_avg( SW_SITE *SW_Site, unsigned int n_tr_rgns, LyrIndex n_layers, - unsigned int tr_regions[], + const unsigned int tr_regions[], double swc[], int VegType, LOG_INFO *LogInfo @@ -512,8 +515,10 @@ void transp_weighted_avg( 1-Oct-03 - local sumco replaces previous sum_tr_coeff[] **********************************************************************/ - unsigned int r, i; - double swp, sumco; + unsigned int r; + unsigned int i; + double swp; + double sumco; *swp_avg = 0; for (r = 1; r <= n_tr_rgns; r++) { @@ -644,7 +649,9 @@ void pot_soil_evap( swpotentl - compute soilwater potential **********************************************************************/ - double x, avswp = 0.0, sumwidth = 0.0; + double x; + double avswp = 0.0; + double sumwidth = 0.0; unsigned int i; /* get the weighted average of swp in the evap layers */ @@ -719,7 +726,9 @@ void pot_soil_evap_bs( swpotentl - compute soilwater potential **********************************************************************/ - double x, avswp = 0.0, sumwidth = 0.0; + double x; + double avswp = 0.0; + double sumwidth = 0.0; unsigned int i; /* get the weighted average of swp in the evap layers */ @@ -812,7 +821,9 @@ void pot_transp( tanfunc - tangent function **********************************************************************/ - double par1, par2, shadeaf; + double par1; + double par2; + double shadeaf; if (LE(biolive, 0.)) { *bstrate = 0.; @@ -878,7 +889,9 @@ double watrate( **********************************************************************/ - double par1, par2, result; + double par1; + double par2; + double result; if (LT(petday, .2)) { par1 = 3.0; @@ -965,7 +978,7 @@ void remove_from_soil( SW_SITE *SW_Site, double *aet, unsigned int nlyrs, - double coeff[], + const double coeff[], double rate, double swcmin[], double lyrFrozen[], @@ -984,7 +997,12 @@ HISTORY: 10 Jan 2002 - cwb - replaced two previous functions with **********************************************************************/ unsigned int i; - double swpfrac[MAX_LAYERS], sumswp = 0.0, swc_avail, q, tmpswp, d = 0.; + double swpfrac[MAX_LAYERS]; + double sumswp = 0.0; + double swc_avail; + double q; + double tmpswp; + double d = 0.; for (i = 0; i < nlyrs; i++) { tmpswp = SW_SWRC_SWCtoSWP(swc[i], SW_Site, i, LogInfo); @@ -1061,9 +1079,16 @@ void percolate_unsaturated( ) { unsigned int i; - int j; - double drainlw = 0.0, swc_avail, drainpot, d[MAX_LAYERS] = {0}, push, - kunsat_rel, swcrel, tmp1, tmp2; + unsigned int j; + double drainlw = 0.0; + double swc_avail; + double drainpot; + double d[MAX_LAYERS] = {0}; + double push; + double kunsat_rel; + double swcrel; + double tmp1; + double tmp2; /* Note that this function calculates percolation as if no gravel @@ -1144,8 +1169,10 @@ void percolate_unsaturated( /* adjust (i.e., push water upwards) if water content of a layer is - now above saturated water content */ - for (j = nlyrs - 1; j >= 0; j--) { + now above saturated water content */ + + /* reverse for-loop with j in [nlyrs - 1, 0] */ + for (j = nlyrs; j-- > 0;) { if (GT(swc[j], SW_Site->swcBulk_saturated[j])) { push = swc[j] - SW_Site->swcBulk_saturated[j]; swc[j] -= push; @@ -1195,7 +1222,7 @@ void hydraulic_redistribution( SW_SITE *SW_Site, unsigned int vegk, unsigned int nlyrs, - double lyrFrozen[], + const double lyrFrozen[], double maxCondroot, double swp50, double shapeCond, @@ -1211,19 +1238,27 @@ void hydraulic_redistribution( point 03/23/2012 (drs) excluded hydraulic redistribution from top soil layer (assuming that this layer is <= 5 cm deep) **********************************************************************/ - - unsigned int i, j, idso, idre, nit; - Bool is_hd_adj; - double swa[MAX_LAYERS] = {0}, swp[MAX_LAYERS] = {0}, - relCondroot[MAX_LAYERS] = {0}, mlyrRootCo[2] = {0.}, - hydredmat[MAX_LAYERS][MAX_LAYERS] = {{0}}; - double hdnet, hdin, hdout, tmp; - #ifdef SWDEBUG short debug = 0; double hdnet2; #endif + unsigned int i; + unsigned int j; + unsigned int idso; + unsigned int idre; + unsigned int nit; + Bool is_hd_adj; + double swa[MAX_LAYERS] = {0}; + double swp[MAX_LAYERS] = {0}; + double relCondroot[MAX_LAYERS] = {0}; + double mlyrRootCo[2] = {0.}; + double hydredmat[MAX_LAYERS][MAX_LAYERS] = {{0}}; + double hdnet; + double hdin; + double hdout; + double tmp; + #ifdef SWDEBUG if (debug) { sw_printf("hydred[%d-%d/veg(%d)]: \n", year, doy, vegk); @@ -1469,13 +1504,15 @@ void lyrTemp_to_lyrSoil_temperature( double temperatureRangeR[], double temperatureRange[] ) { - - // i: index to soil temperature layer (i = 0 is surface) - // j: index to soil layer (j = 0 is first soil layer) - unsigned int i = 0, j, n; #ifdef SWDEBUG int debug = 0; #endif + + // i: index to soil temperature layer (i = 0 is surface) + // j: index to soil layer (j = 0 is first soil layer) + unsigned int i = 0; + unsigned int j; + unsigned int n; double acc; // interpolate soil temperature values for depth of soil profile layers @@ -1570,20 +1607,23 @@ depths/layers. */ void lyrSoil_to_lyrTemp_temperature( unsigned int nlyrSoil, - double depth_Soil[], - double avgLyrTemp[], + const double depth_Soil[], + const double avgLyrTemp[], double endTemp, unsigned int nlyrTemp, double depth_Temp[], double maxTempDepth, double avgLyrTempR[] ) { - - unsigned int i, j1 = 0, j2; #ifdef SWDEBUG int debug = 0; #endif - double depth_Soil2[MAX_LAYERS + 1] = {0}, avgLyrTemp2[MAX_LAYERS + 1] = {0}; + + unsigned int i; + unsigned int j1 = 0; + unsigned int j2; + double depth_Soil2[MAX_LAYERS + 1] = {0}; + double avgLyrTemp2[MAX_LAYERS + 1] = {0}; // transfer data to include bottom conditions; do not include surface // temperature in interpolations @@ -1671,25 +1711,28 @@ to soil temperature layer values. void lyrSoil_to_lyrTemp( double cor[MAX_ST_RGR][MAX_LAYERS + 1], unsigned int nlyrSoil, - double width_Soil[], - double var[], + const double width_Soil[], + const double var[], unsigned int nlyrTemp, double width_Temp, double res[] ) { - - unsigned int i, j = 0; #ifdef SWDEBUG int debug = 0; #endif - double acc, ratio, sum; + + unsigned int i; + unsigned int j = 0; + double acc; + double ratio; + double sum; for (i = 0; i < nlyrTemp + 1; i++) { res[i] = 0.0; acc = 0.0; sum = 0.0; while (LT(acc, width_Temp) && j < nlyrSoil + 1) { - if (GE(cor[i][j], 0.0)) { + if (GE(cor[i][j], 0.0) && j < nlyrSoil) { // there are soil layers to add ratio = cor[i][j] / width_Soil[j]; res[i] += var[j] * ratio; @@ -1701,8 +1744,10 @@ void lyrSoil_to_lyrTemp( } else if (LT(cor[i][j], 0.0)) { // negative cor values indicate end of soil layer profile // copying values from deepest soil layer - ratio = -cor[i][j] / width_Soil[j - 1]; - res[i] += var[j - 1] * ratio; + // NOLINTBEGIN(clang-analyzer-core.UndefinedBinaryOperatorResult) + ratio = -cor[i][j] / width_Soil[nlyrSoil - 1]; + res[i] += var[nlyrSoil - 1] * ratio; + // NOLINTEND(clang-analyzer-core.UndefinedBinaryOperatorResult) sum += ratio; acc += (-cor[i][j]); } @@ -1742,15 +1787,17 @@ double surface_temperature_under_snow(double airTempAvg, double snow) { double kSnow; // the effect of snow based on swe double tSoilAvg = 0.0; // the average temeperature of the soil surface // Parton et al. 1998. Equation 6. - if (snow == 0) { - return 0.0; - } else if (snow > 0 && airTempAvg >= 0) { - tSoilAvg = -2.0; - } else if (snow > 0 && airTempAvg < 0) { - // Parton et al. 1998. Equation 5. - kSnow = fmax((-0.15 * snow + 1.0), 0.0); - tSoilAvg = 0.3 * airTempAvg * kSnow + -2.0; + + if (snow > 0) { + if (airTempAvg >= 0) { + tSoilAvg = -2.0; + } else { + // Parton et al. 1998. Equation 5. + kSnow = fmax((-0.15 * snow + 1.0), 0.0); + tSoilAvg = 0.3 * airTempAvg * kSnow + -2.0; + } } + return tSoilAvg; } @@ -1799,13 +1846,12 @@ void SW_ST_setup_run( double *lyrFrozen, LOG_INFO *LogInfo ) { - - LyrIndex i; - #ifdef SWDEBUG int debug = 0; #endif + LyrIndex i; + if (!(*soil_temp_init)) { #ifdef SWDEBUG if (debug) { @@ -1896,8 +1942,8 @@ void soil_temperature_setup( double avgLyrTempInit[], double sTconst, unsigned int nlyrs, - double fc[], - double wp[], + const double fc[], + const double wp[], double deltaX, double theMaxDepth, unsigned int nRgr, @@ -1906,15 +1952,21 @@ void soil_temperature_setup( Bool *soil_temp_init, LOG_INFO *LogInfo ) { - - // local vars - unsigned int x1 = 0, x2 = 0, j = 0, i; #ifdef SWDEBUG int debug = 0; #endif - double d1 = 0.0, d2 = 0.0, acc = 0.0; + + // local vars + unsigned int x1 = 0; + unsigned int x2 = 0; + unsigned int j = 0; + unsigned int i; + double d1 = 0.0; + double d2 = 0.0; + double acc = 0.0; // double fc_vwc[nlyrs], wp_vwc[nlyrs]; - double fc_vwc[MAX_LAYERS] = {0}, wp_vwc[MAX_LAYERS] = {0}; + double fc_vwc[MAX_LAYERS] = {0}; + double wp_vwc[MAX_LAYERS] = {0}; // set `soil_temp_init` to 1 to indicate that this function was already // called and shouldn't be called again @@ -2165,7 +2217,7 @@ void set_frozen_unfrozen( double avgLyrTemp[], double swc[], double swc_sat[], - double width[], + const double width[], double lyrFrozen[] ) { @@ -2199,7 +2251,7 @@ Based on equations from Eitzinger 2000. @cite Eitzinger2000 @param vwc An array of temperature-layer VWC values (cm/layer). @param bDensity An array of the bulk density of the whole soil per soil layer (g/cm3). -@param[in] fusion_pool_init Specifies if the values for the soil fusion +@param[in,out] fusion_pool_init Specifies if the values for the soil fusion (thawing/freezing) section of `soil_temperature()` have been initialized @param oldsFusionPool_actual Yesterdays actual fusion pool at each soil layer @@ -2207,13 +2259,13 @@ Based on equations from Eitzinger 2000. @cite Eitzinger2000 freezing/thawing */ unsigned int adjust_Tsoil_by_freezing_and_thawing( - double oldavgLyrTemp[], - double avgLyrTemp[], + const double oldavgLyrTemp[], + const double avgLyrTemp[], double shParam, unsigned int nlyrs, - double vwc[], - double bDensity[], - Bool fusion_pool_init, + const double vwc[], + const double bDensity[], + Bool *fusion_pool_init, double oldsFusionPool_actual[] ) { // Calculate fusion pools based on soil profile layers, soil @@ -2227,13 +2279,16 @@ unsigned int adjust_Tsoil_by_freezing_and_thawing( // double deltaTemp, Cis, sFusionPool[nlyrs], sFusionPool_actual[nlyrs]; // To avoid compiler warnings "warning: parameter set but not used" - double temp; - temp = oldavgLyrTemp[0] + avgLyrTemp[0] + shParam + nlyrs + vwc[0] + - bDensity[0]; - temp += temp; + (void) oldavgLyrTemp; + (void) avgLyrTemp; + (void) shParam; + (void) nlyrs; + (void) vwc; + (void) bDensity; // end avoid compiler warnings - unsigned int i, sFadjusted_avgLyrTemp; + unsigned int i; + unsigned int sFadjusted_avgLyrTemp; /* local variables explained: debug - 1 to print out debug messages & then exit the program after @@ -2252,11 +2307,11 @@ unsigned int adjust_Tsoil_by_freezing_and_thawing( */ - if (!fusion_pool_init) { + if (!(*fusion_pool_init)) { for (i = 0; i < nlyrs; i++) { oldsFusionPool_actual[i] = 0.; } - fusion_pool_init = swTRUE; + *fusion_pool_init = swTRUE; } sFadjusted_avgLyrTemp = 0; @@ -2359,30 +2414,23 @@ void soil_temperature_today( double deltaX, double sT1, double sTconst, - int nRgr, + unsigned int nRgr, double avgLyrTempR[], - double oldavgLyrTempR[], - double vwcR[], - double wpR[], - double fcR[], - double bDensityR[], + const double oldavgLyrTempR[], + const double vwcR[], + const double wpR[], + const double fcR[], + const double bDensityR[], double csParam1, double csParam2, double shParam, Bool *ptr_stError, double surface_range, double temperatureRangeR[], - double depthsR[], + const double depthsR[], TimeInt year, TimeInt doy ) { - - int i, k, m, Nsteps_per_day = 1; - double pe, cs, sh, dT_to_dX2, alpha, part2; - double oldavgLyrTempR2[MAX_ST_RGR]; - - Bool Tsoil_not_exploded = swTRUE; - #ifdef SWDEBUG int debug = 0; if (year == 1981 && doy > 180 && doy < 191) { @@ -2394,6 +2442,20 @@ void soil_temperature_today( (void) doy; #endif + unsigned int i; + unsigned int k; + unsigned int m; + unsigned int Nsteps_per_day = 1; + double pe; + double cs; + double sh; + double dT_to_dX2; + double alpha; + double part2; + double oldavgLyrTempR2[MAX_ST_RGR]; + + Bool Tsoil_not_exploded = swTRUE; + // upper boundary condition; index 0 indicates surface and not first layer // --> required for interpolation from soil temperature layers to soil // layers @@ -2855,17 +2917,22 @@ void soil_temperature( Bool *ptr_stError, LOG_INFO *LogInfo ) { - - unsigned int i, sFadjusted_avgLyrTemp; #ifdef SWDEBUG int debug = 0; if (year == 1980 && doy < 10) { debug = 0; } #endif - double oldavgLyrTemp[MAX_LAYERS], vwc[MAX_LAYERS], vwcR[MAX_ST_RGR], - avgLyrTempR[MAX_ST_RGR], temperatureRangeR[MAX_ST_RGR], - temperatureRange[MAX_LAYERS], surface_range; + + unsigned int i; + unsigned int sFadjusted_avgLyrTemp; + double oldavgLyrTemp[MAX_LAYERS]; + double vwc[MAX_LAYERS]; + double vwcR[MAX_ST_RGR]; + double avgLyrTempR[MAX_ST_RGR]; + double temperatureRangeR[MAX_ST_RGR]; + double temperatureRange[MAX_LAYERS]; + double surface_range; /* local variables explained: debug - 1 to print out debug messages & then exit the program after @@ -3142,7 +3209,7 @@ void soil_temperature( nlyrs, vwc, bDensity, - SW_StRegValues->fusion_pool_init, + &SW_StRegValues->fusion_pool_init, SW_StRegValues->oldsFusionPool_actual ); diff --git a/src/SW_Flow_lib_PET.c b/src/SW_Flow_lib_PET.c index a630b2fa8..c89882cf2 100644 --- a/src/SW_Flow_lib_PET.c +++ b/src/SW_Flow_lib_PET.c @@ -50,7 +50,8 @@ static const double G_sc = 118.1088; @param[in,out] SW_AtmDem Memoized variables pertaining to atmospheric demand */ void SW_PET_init_run(SW_ATMD *SW_AtmDem) { - int k1, k2; + int k1; + int k2; for (k1 = 0; k1 < 366; k1++) { SW_AtmDem->memoized_G_o[k1][0] = SW_MISSING; @@ -204,8 +205,8 @@ void sun_hourangles( double int_cos_theta[], double int_sin_beta[] ) { - unsigned int i, - doy0 = doy - 1; // doy is base1 + unsigned int i; + unsigned int doy0 = doy - 1; // doy is base1 Bool isTrue = swFALSE; if (missing(SW_AtmDem->msun_angles[doy0][0])) { @@ -214,9 +215,32 @@ void sun_hourangles( // effects static const double tol = 1e-9; - double declin, a, b, c, g, h, f1, f2, f3, f4, f5, tmp, tmp1, tmp2, tmp3, - X, omega1, trig_omega1, omega1b, cos_theta1b, omega2, trig_omega2, - omega2b, cos_theta2b, cos_theta_sunrise, cos_theta_sunset; + double declin; + double a; + double b; + double c; + double g; + double h; + double f1; + double f2; + double f3; + double f4; + double f5; + double tmp; + double tmp1; + double tmp2; + double tmp3; + double X; + double omega1; + double trig_omega1; + double omega1b; + double cos_theta1b; + double omega2; + double trig_omega2; + double omega2b; + double cos_theta2b; + double cos_theta_sunrise; + double cos_theta_sunset; // Calculate solar declination @@ -325,8 +349,12 @@ void sun_hourangles( #ifndef sun_hourangles_Duffie2013_2205 // Use Allen et al. 2006 to calculate tilted sunrise/sunset - double omega1x, cos_theta1, cos_theta1x, omega2x, cos_theta2, - cos_theta2x; + double omega1x; + double cos_theta1; + double cos_theta1x; + double omega2x; + double cos_theta2; + double cos_theta2x; // Candidate sunrise and sunset hour angles on tilted surface cos_theta1 = -a + b * cos(omega1) + c * sin(omega1); @@ -746,7 +774,9 @@ as cited by Allen et al. 2006 @cite allen2006AaFM @return Clearness index of direct beam radiation for cloudless conditions [-] */ double clearsky_directbeam(double P, double e_a, double int_sin_beta) { - double W, Kt = 1., K_b; + double W; + double Kt = 1.; + double K_b; /* Allen et al. 2006: "Kt is an empirical turbidity coefficient, 0 < Kt <= 1.0 where Kt = 1.0 for clean air (typical of regions of @@ -899,10 +929,29 @@ double solar_radiation( double *H_gh, LOG_INFO *LogInfo ) { - double P, sun_angles[7], int_cos_theta[2], int_sin_beta[2], H_o[2], - k_c = SW_MISSING, dl, convert_rsds_to_H_gh = 1., tau_h_obs, H_bh_calc, - H_dh_calc, K_bh_calc, K_dh_calc, K_bh_obs, K_dh_obs, H_bt, H_dt, H_rt, - K_bt_calc, f_ia, f_i, f_B, H_g; + double P; + double sun_angles[7]; + double int_cos_theta[2]; + double int_sin_beta[2]; + double H_o[2]; + double k_c = SW_MISSING; + double dl; + double convert_rsds_to_H_gh = 1.; + double tau_h_obs; + double H_bh_calc; + double H_dh_calc; + double K_bh_calc; + double K_dh_calc; + double K_bh_obs; + double K_dh_obs; + double H_bt; + double H_dt; + double H_rt; + double K_bt_calc; + double f_ia; + double f_i; + double f_B; + double H_g; //--- Calculate daily integration of cos(theta) and sin(beta) @@ -1199,7 +1248,13 @@ The slope of the svp-T curve is obtained by derivation for temperature. @return Saturation vapor pressure [kPa] */ double svp(double T, double *slope_svp_to_t) { - double tmp, tmp0, tmp1, tmp2, tmp3, dp, svp; + double tmp; + double tmp0; + double tmp1; + double tmp2; + double tmp3; + double dp; + double svp; if (T > 0) { // Derivation for Huang 2018: eq. 17 @@ -1324,7 +1379,16 @@ double petfunc( LOG_INFO *LogInfo ) { - double Ea, Rn, Rc, Rbb, delta, clrsky, ea, P_kPa, gamma, pet; + double Ea; + double Rn; + double Rc; + double Rbb; + double delta; + double clrsky; + double ea; + double P_kPa; + double gamma; + double pet; /* Unit conversion factors: 1 langley = 1 ly = 41840 J/m2 = 0.0168 evaporative-mm @@ -1337,12 +1401,18 @@ double petfunc( static const double // [mmHg / F] = [kPa / K] * [mmHg / kPa] = // = [kPa / K] * (760. / 101.325) - convert_kPa__to__mmHg = 7.5006168, + convert_kPa__to__mmHg = 7.5006168; + static const double + // [mmHg / F] = [kPa / K] * [mmHg / kPa] = + // = [kPa / K] * (760. / 101.325) // [miles / day] = [m / s] * [miles / m] * [s / day] = // = [m / s] * (1 / 1609.344) * 86400 - convert_m_per_s__to__miles_per_day = 53.686471, + convert_m_per_s__to__miles_per_day = 53.686471; + static const double + // [mmHg / F] = [kPa / K] * [mmHg / kPa] = + // = [kPa / K] * (760. / 101.325) // [langley] = [evaporative mm] * [kJ / m2] / [heat of vaporization] = // = [evaporative mm] * (41.840) / 2490 // 2490 [kJ/kg heat of vaporization at about T = 10-15 C], see also @@ -1351,8 +1421,11 @@ double petfunc( // [W / m2] = [evaporative mm / day] * [kJ / s / m2] * [s / day] / [heat // of vaporization] = // [evaporative mm / day] * 1e-3 * 86400 / 2490 - convert_W_per_m2__to__mm_per_day = 0.0346988, + convert_W_per_m2__to__mm_per_day = 0.0346988; + static const double + // [mmHg / F] = [kPa / K] * [mmHg / kPa] = + // = [kPa / K] * (760. / 101.325) // [MJ / m2] = [evaporative mm / day] * [1e3 kJ / m2] / [heat of // vaporization] = // [evaporative mm / day] * 1e3 / 2490 diff --git a/src/SW_Main.c b/src/SW_Main.c index 35c9720de..aeb0f664e 100644 --- a/src/SW_Main.c +++ b/src/SW_Main.c @@ -19,7 +19,6 @@ #include "include/generic.h" // for Bool, swFALSE, swTRUE #include "include/SW_Control.h" // for SW_CTL_RunSimSet, SW_CTL_clear_m... #include "include/SW_datastructs.h" // for LOG_INFO, SW_RUN, SW_DOMAIN, SW_... -#include "include/SW_Defines.h" // for SW_OUTNKEYS #include "include/SW_Domain.h" // for SW_DOM_deconstruct, SW_DOM_init_... #include "include/SW_Files.h" // for eFirst #include "include/SW_Main_lib.h" // for sw_fail_on_error, sw_init_args @@ -55,7 +54,6 @@ int main(int argc, char **argv) { unsigned long userSUID; - // Start overall wall time SW_WT_StartTime(&SW_WallTime); @@ -185,7 +183,7 @@ int main(int argc, char **argv) { } if (EchoInits) { - _echo_all_inputs(&sw_template, &SW_Domain.OutDom); + echo_all_inputs(&sw_template, &SW_Domain.OutDom); } // run simulations: loop over simulation set diff --git a/src/SW_Main_lib.c b/src/SW_Main_lib.c index 4a8fbf5bb..eff30f983 100644 --- a/src/SW_Main_lib.c +++ b/src/SW_Main_lib.c @@ -23,8 +23,8 @@ #include "include/SW_datastructs.h" // for LOG_INFO #include "include/SW_Defines.h" // for MAX_MSGS, MAX_LOG_SIZE, BUILD_DATE #include // for fprintf, stderr, fflush, stdout -#include // for atof, atoll, exit, free, EXIT_FA... -#include // for strcpy, strncmp +#include // for exit, free, EXIT_FA... +#include // for strncmp #ifdef RSOILWAT #include // for error(), and warning() from @@ -106,7 +106,7 @@ void sw_print_version(void) { @param[in] argc Number (count) of command line arguments. @param[in] argv Values of command line arguments. @param[out] EchoInits Flag to control if inputs are to be output to the user -@param[out] _firstfile First file name to be filled in the program run +@param[out] firstfile First file name to be filled in the program run @param[out] userSUID Simulation Unit Identifier requested by the user (base1); 0 indicates that all simulations units within domain are requested @param[out] wallTimeLimit Terminate simulations early when @@ -120,7 +120,7 @@ void sw_init_args( int argc, char **argv, Bool *EchoInits, - char **_firstfile, + char **firstfile, unsigned long *userSUID, double *wallTimeLimit, Bool *renameDomainTemplateNC, @@ -141,6 +141,7 @@ void sw_init_args( * at end of program. */ char str[1024]; + const char *errMsg = "command-line"; /* valid options */ char const *opts[] = {"-d", "-f", "-e", "-q", "-v", "-h", "-s", "-t", "-r"}; @@ -148,13 +149,14 @@ void sw_init_args( /* indicates options with values: 0=none, 1=required, -1=optional */ int valopts[] = {1, 1, 0, 0, 0, 0, 1, 1, 0}; - int i, /* looper through all cmdline arguments */ - a, /* current valid argument-value position */ - op, /* position number of found option */ - nopts = sizeof(opts) / sizeof(char *); + int i; /* looper through all cmdline arguments */ + int a; /* current valid argument-value position */ + int op; /* position number of found option */ + int nopts = sizeof(opts) / sizeof(char *); + double doubleUserSUID = 0.; /* Defaults */ - *_firstfile = Str_Dup(DFLT_FIRSTFILE, LogInfo); + *firstfile = Str_Dup(DFLT_FIRSTFILE, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -180,117 +182,128 @@ void sw_init_args( sw_print_usage(); LogError(LogInfo, LOGERROR, "\nInvalid option %s\n", argv[a]); return; // Exit function prematurely due to error + } - } else { - // Use `valopts[op]` in else-branch to avoid - // `warning: array subscript 6 is above array bounds of 'int[6]' - // [-Warray-bounds]` - - *str = '\0'; - /* extract value part of option-value pair */ - if (valopts[op]) { - if ('\0' != argv[a][2]) { - /* no space betw opt-value */ - strcpy(str, (argv[a] + 2)); - - } else if ('-' != *argv[a + 1]) { - /* space betw opt-value */ - strcpy(str, argv[++a]); - - } else if (0 < valopts[op]) { - /* required opt-val not found */ - sw_print_usage(); - LogError( - LogInfo, LOGERROR, "\nIncomplete option %s\n", opts[op] - ); - return; // Exit function prematurely due to error - } - /* opt-val not required */ - } + // Use `valopts[op]` in else-branch to avoid + // `warning: array subscript 6 is above array bounds of 'int[6]' + // [-Warray-bounds]` + + *str = '\0'; + /* extract value part of option-value pair */ + if (valopts[op]) { + if ('\0' != argv[a][2]) { + /* no space betw opt-value */ + (void) snprintf(str, sizeof str, "%s", (argv[a] + 2)); + + } else if ('-' != *argv[a + 1]) { + /* space betw opt-value */ + (void) snprintf(str, sizeof str, "%s", argv[++a]); - /* tell us what to do here */ - /* set indicators/variables based on results */ - switch (op) { - case 0: /* -d */ - if (!ChDir(str)) { - LogError( - LogInfo, LOGERROR, "Invalid project directory (%s)", str - ); - return; // Exit function prematurely due to error - } - break; - - case 1: /* -f */ - free(*_firstfile); - *_firstfile = Str_Dup(str, LogInfo); - if (LogInfo->stopRun) { - return; // Exit function prematurely due to error - } - break; - - case 2: /* -e */ - *EchoInits = swTRUE; - break; - - case 3: /* -q */ - LogInfo->QuietMode = swTRUE; - break; - - case 4: /* -v */ - sw_print_version(); - LogError(LogInfo, LOGERROR, ""); - if (LogInfo->stopRun) { - return; // Exit function prematurely due to error - } - break; - - case 5: /* -h */ + } else if (0 < valopts[op]) { + /* required opt-val not found */ sw_print_usage(); - LogError(LogInfo, LOGERROR, ""); - if (LogInfo->stopRun) { - return; // Exit function prematurely due to error - } - break; - - case 6: /* -s */ - *userSUID = atoll(str); - /* Check that user input can be represented by userSUID - * (currently, unsigned long) */ - /* Expect that conversion of string to double results in the - * same value as conversion of userSUID to double */ - if (!EQ(atof(str), (double) *userSUID)) { - LogError( - LogInfo, - LOGERROR, - "User input not recognized as a simulation unit " - "('-s %s' vs. %lu).", - str, - *userSUID - ); - return; // Exit function prematurely due to error - } - break; - - case 7: /* -t */ - *wallTimeLimit = atof(str); - break; - - case 8: /* -r */ - *renameDomainTemplateNC = swTRUE; - break; - - default: + LogError( + LogInfo, LOGERROR, "\nIncomplete option %s\n", opts[op] + ); + return; // Exit function prematurely due to error + } + /* opt-val not required */ + } + + /* tell us what to do here */ + /* set indicators/variables based on results */ + switch (op) { + case 0: /* -d */ + if (!ChDir(str)) { + LogError( + LogInfo, LOGERROR, "Invalid project directory (%s)", str + ); + return; // Exit function prematurely due to error + } + break; + + case 1: /* -f */ + free(*firstfile); + *firstfile = Str_Dup(str, LogInfo); + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + break; + + case 2: /* -e */ + *EchoInits = swTRUE; + break; + + case 3: /* -q */ + LogInfo->QuietMode = swTRUE; + break; + + case 4: /* -v */ + sw_print_version(); + LogError(LogInfo, LOGERROR, ""); + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + break; + + case 5: /* -h */ + sw_print_usage(); + LogError(LogInfo, LOGERROR, ""); + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + break; + + case 6: /* -s */ + *userSUID = sw_strtoul(str, errMsg, LogInfo); + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + /* Check that user input can be represented by userSUID + * (currently, unsigned long) */ + /* Expect that conversion of string to double results in the + * same value as conversion of userSUID to double */ + doubleUserSUID = sw_strtod(str, errMsg, LogInfo); + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + if (!EQ(doubleUserSUID, (double) *userSUID)) { LogError( LogInfo, LOGERROR, - "Programmer: bad option in main:sw_init_args:switch" + "User input not recognized as a simulation unit " + "('-s %s' vs. %lu).", + str, + *userSUID ); + return; // Exit function prematurely due to error + } + break; + case 7: /* -t */ + *wallTimeLimit = sw_strtod(str, errMsg, LogInfo); + if (LogInfo->stopRun) { return; // Exit function prematurely due to error } + break; - a++; /* move to next valid arg-value position */ + case 8: /* -r */ + *renameDomainTemplateNC = swTRUE; + break; + + default: + LogError( + LogInfo, + LOGERROR, + "Programmer: bad option in main:sw_init_args:switch" + ); + + return; // Exit function prematurely due to error } + + a++; /* move to next valid arg-value position */ } /* end for(i) */ } @@ -312,7 +325,7 @@ void sw_fail_on_error(LOG_INFO *LogInfo) { #else if (LogInfo->stopRun) { if (!LogInfo->QuietMode) { - fprintf(stderr, "%s", LogInfo->errorMsg); + (void) fprintf(stderr, "%s", LogInfo->errorMsg); } if (LogInfo->printProgressMsg) { sw_message("ended."); @@ -352,7 +365,8 @@ simulation run */ void sw_write_warnings(const char *header, LOG_INFO *LogInfo) { - int warnMsgNum, warningUpperBound = LogInfo->numWarnings; + int warnMsgNum; + int warningUpperBound = LogInfo->numWarnings; Bool tooManyWarns = swFALSE; char tooManyWarnsStr[MAX_LOG_SIZE]; @@ -361,7 +375,7 @@ void sw_write_warnings(const char *header, LOG_INFO *LogInfo) { warningUpperBound = MAX_MSGS; tooManyWarns = swTRUE; - snprintf( + (void) snprintf( tooManyWarnsStr, MAX_LOG_SIZE, "There were a total of %d warnings and only %d were printed.\n", @@ -384,26 +398,47 @@ void sw_write_warnings(const char *header, LOG_INFO *LogInfo) { } } #else + int writeRes = 0; + /* SOILWAT2: do print warnings and don't notify user if quiet */ if (!isnull(LogInfo->logfp)) { for (warnMsgNum = 0; warnMsgNum < warningUpperBound; warnMsgNum++) { - fprintf( + writeRes = fprintf( LogInfo->logfp, "%s%s", header, LogInfo->warningMsgs[warnMsgNum] ); + + if (writeRes < 0) { + goto writeErrMsg; + } } if (tooManyWarns) { - fprintf(LogInfo->logfp, "%s%s", header, tooManyWarnsStr); + writeRes = fprintf(LogInfo->logfp, "%s%s", header, tooManyWarnsStr); + if (writeRes < 0) { + goto writeErrMsg; + } } if (LogInfo->stopRun) { /* Write error message to log file here; later (sw_fail_on_error()), we will write it to stderr and crash */ - fprintf(LogInfo->logfp, "%s%s", header, LogInfo->errorMsg); + writeRes = + fprintf(LogInfo->logfp, "%s%s", header, LogInfo->errorMsg); + if (writeRes < 0) { + goto writeErrMsg; + } } - fflush(LogInfo->logfp); + writeRes = fflush(LogInfo->logfp); + + writeErrMsg: { + if (writeRes < 0) { + sw_message( + "Failed to write all warning/error messages to logfile.\n" + ); + } + } } #endif } @@ -428,10 +463,11 @@ void sw_wrapup_logs(LOG_INFO *LogInfo) { if ((LogInfo->numDomainErrors > 0 || LogInfo->numDomainWarnings > 0 || LogInfo->stopRun || LogInfo->numWarnings > 0) && !QuietMode && LogInfo->logfp != stdout && LogInfo->logfp != stderr) { - fprintf(stderr, "\nCheck logfile for warnings and error messages.\n"); + (void + ) fprintf(stderr, "\nCheck logfile for warnings and error messages.\n"); if (LogInfo->numDomainWarnings > 0) { - fprintf( + (void) fprintf( stderr, "Simulation units with warnings: n = %lu\n", LogInfo->numDomainWarnings @@ -439,7 +475,7 @@ void sw_wrapup_logs(LOG_INFO *LogInfo) { } if (LogInfo->numDomainErrors > 0) { - fprintf( + (void) fprintf( stderr, "Simulation units with an error: n = %lu\n", LogInfo->numDomainErrors diff --git a/src/SW_Markov.c b/src/SW_Markov.c index fa430d365..2990cfb07 100644 --- a/src/SW_Markov.c +++ b/src/SW_Markov.c @@ -22,7 +22,7 @@ /* --------------------------------------------------- */ #include "include/SW_Markov.h" // for SW_MKV_construct, SW_MKV_deconst... #include "include/filefuncs.h" // for LogError, CloseFile, GetALine -#include "include/generic.h" // for RealD, RealF, LOGERROR, swFALSE +#include "include/generic.h" // for LOGERROR, swFALSE #include "include/myMemory.h" // for Mem_Calloc, Mem_Copy #include "include/rands.h" // for RandNorm, RandSeed, RandUni #include "include/SW_datastructs.h" // for SW_MARKOV, LOG_INFO @@ -30,7 +30,7 @@ #include "include/SW_Files.h" // for eMarkovCov, eMarkovProb #include "include/Times.h" // for doy2week #include // for isfinite -#include // for NULL, fopen, sscanf, FILE, size_t +#include // for NULL, sscanf, FILE, size_t #include // for free /* =================================================== */ @@ -67,13 +67,13 @@ All temperature values are in units of degree Celsius. @return tmin The corrected minimum temperature, i.e., tmin + cfmin. */ static void temp_correct_wetdry( - RealD *tmax, - RealD *tmin, - RealD rain, - RealD cfmax_wet, - RealD cfmax_dry, - RealD cfmin_wet, - RealD cfmin_dry + double *tmax, + double *tmin, + double rain, + double cfmax_wet, + double cfmax_dry, + double cfmin_wet, + double cfmin_dry ) { if (GT(rain, 0.)) { @@ -92,9 +92,11 @@ static void temp_correct_wetdry( #ifdef SWDEBUG // since `temp_correct_wetdry` is static we cannot do unit tests unless we set // it up as an externed function pointer +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) void (*test_temp_correct_wetdry)( - RealD *, RealD *, RealD, RealD, RealD, RealD, RealD + double *, double *, double, double, double, double, double ) = &temp_correct_wetdry; +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) #endif @@ -119,13 +121,13 @@ void (*test_temp_correct_wetdry)( @return Daily minimum (*tmin) and maximum (*tmax) temperature. */ static void mvnorm( - RealD *tmax, - RealD *tmin, - RealD wTmax, - RealD wTmin, - RealD wTmax_var, - RealD wTmin_var, - RealD wT_covar, + double *tmax, + double *tmin, + double wTmax, + double wTmin, + double wTmax_var, + double wTmin_var, + double wT_covar, sw_random_t *markov_rng, LOG_INFO *LogInfo ) { @@ -142,10 +144,15 @@ static void mvnorm( * after some extensive debugging in this and the * RandNorm() function, it seems silly to maintain * the extra function call. - * cwb - 24-Oct-03 -- Note the switch to double (RealD). + * cwb - 24-Oct-03 -- Note the switch to double (double). * C converts the floats transparently. */ - RealD s, z1, z2, wTmax_sd, vc10, vc11; + double s; + double z1; + double z2; + double wTmax_sd; + double vc10; + double vc11; // Gentle, J. E. 2009. Computational statistics. Springer, Dordrecht; New // York. @@ -196,8 +203,10 @@ static void mvnorm( #ifdef SWDEBUG // since `mvnorm` is static we cannot do unit tests unless we set it up // as an externed function pointer -void (*test_mvnorm)(RealD *, RealD *, RealD, RealD, RealD, RealD, RealD, sw_random_t *, LOG_INFO *) = +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) +void (*test_mvnorm)(double *, double *, double, double, double, double, double, sw_random_t *, LOG_INFO *) = &mvnorm; +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) #endif @@ -254,48 +263,52 @@ void SW_MKV_construct(unsigned long rng_seed, SW_MARKOV *SW_Markov) { @param[out] LogInfo Holds information on warnings and errors */ void allocateMKV(SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { - size_t s = sizeof(RealD); + size_t s = sizeof(double); SW_Markov->wetprob = - (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } SW_Markov->dryprob = - (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } SW_Markov->avg_ppt = - (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } SW_Markov->std_ppt = - (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } - SW_Markov->cfxw = (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + SW_Markov->cfxw = + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } - SW_Markov->cfxd = (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + SW_Markov->cfxd = + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } - SW_Markov->cfnw = (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + SW_Markov->cfnw = + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } - SW_Markov->cfnd = (RealD *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); + SW_Markov->cfnd = + (double *) Mem_Calloc(MAX_DAYS, s, "allocateMKV", LogInfo); } /** Free dynamically allocated memory in SW_MARKOV @@ -363,7 +376,7 @@ void SW_MKV_deconstruct(SW_MARKOV *SW_Markov) { deallocateMKV(SW_Markov); } for the weather generator */ void copyMKV(SW_MARKOV *dest_MKV, SW_MARKOV *template_MKV) { - size_t s = sizeof(RealD) * MAX_DAYS; /* see `allocateMKV()` */ + size_t s = sizeof(double) * MAX_DAYS; /* see `allocateMKV()` */ Mem_Copy(dest_MKV->wetprob, template_MKV->wetprob, s); Mem_Copy(dest_MKV->dryprob, template_MKV->dryprob, s); @@ -395,22 +408,24 @@ void SW_MKV_today( SW_MARKOV *SW_Markov, TimeInt doy0, TimeInt year, - RealD *tmax, - RealD *tmin, - RealD *rain, + double *tmax, + double *tmin, + double *rain, LOG_INFO *LogInfo ) { /* =================================================== */ /* enter with rain == yesterday's ppt, doy0 as array index: [0, 365] = doy - * 1 leave with rain == today's ppt */ - TimeInt week; - RealF prob, p, x; - #ifdef SWDEBUG short debug = 0; #endif + TimeInt week; + double prob; + double p; + double x; + #ifdef SWDEBUG if (debug) { sw_printf( @@ -519,15 +534,28 @@ Bool SW_MKV_read_prob( ) { /* =================================================== */ const int nitems = 5; + const int numFloatInStrings = 4; + FILE *f; - int lineno = 0, day, x; - RealF wet, dry, avg, std; + int lineno = 0; + int day; + int x; + int index; + double wet; + double dry; + double avg; + double std; + double *doubleVals[4] = {&wet, &dry, &avg, &std}; char inbuf[MAX_FILENAMESIZE]; + char dayStr[4] = {'\0'}; + char inDoubleStrs[4][20] = {{'\0'}}; + + Bool result = swTRUE; /* note that Files.read() must be called prior to this. */ char *MyFileName = InFiles[eMarkovProb]; - - if (NULL == (f = fopen(MyFileName, "r"))) { + f = OpenFile(MyFileName, "r", LogInfo); + if (LogInfo->stopRun) { return swFALSE; } @@ -536,11 +564,33 @@ Bool SW_MKV_read_prob( break; /* skip extra lines */ } - x = sscanf(inbuf, "%d %f %f %f %f", &day, &wet, &dry, &avg, &std); + x = sscanf( + inbuf, + "%3s %19s %19s %19s %19s", + dayStr, + inDoubleStrs[0], + inDoubleStrs[1], + inDoubleStrs[2], + inDoubleStrs[3] + ); + + day = sw_strtoi(dayStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + result = swFALSE; + goto closeFile; + } + + for (index = 0; index < numFloatInStrings; index++) { + *(doubleVals[index]) = + sw_strtod(inDoubleStrs[index], MyFileName, LogInfo); + if (LogInfo->stopRun) { + result = swFALSE; + goto closeFile; + } + } // Check that text file is ok: if (x < nitems) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -549,14 +599,14 @@ Bool SW_MKV_read_prob( lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Check that input values meet requirements: // day is a real calendar day if (!isfinite((float) day) || day < 1 || day > MAX_DAYS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -566,13 +616,13 @@ Bool SW_MKV_read_prob( lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Probabilities are in [0, 1] if (!isfinite(wet) || LT(wet, 0.) || GT(wet, 1.) || !isfinite(dry) || LT(dry, 0.) || GT(dry, 1.)) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -584,12 +634,12 @@ Bool SW_MKV_read_prob( lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Mean and SD of daily precipitation are >= 0 if (!isfinite(avg) || LT(avg, 0.) || !isfinite(std) || LT(std, 0.)) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -601,7 +651,8 @@ Bool SW_MKV_read_prob( lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Store values in `SW_Markov` @@ -617,9 +668,9 @@ Bool SW_MKV_read_prob( SW_Markov->std_ppt[day] = std; } - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } - return swTRUE; + return result; } /** @@ -637,13 +688,32 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { /* =================================================== */ const int nitems = 11; FILE *f; - int lineno = 0, week, x; + int lineno = 0; + int week; + int x; + int index; char inbuf[MAX_FILENAMESIZE]; - RealF t1, t2, t3, t4, t5, t6, cfxw, cfxd, cfnw, cfnd; + double t1; + double t2; + double t3; + double t4; + double t5; + double t6; + double cfxw; + double cfxd; + double cfnw; + double cfnd; + double *doubleVals[] = { + &t1, &t2, &t3, &t4, &t5, &t6, &cfxw, &cfxd, &cfnw, &cfnd + }; + char weekStr[3] = {'\0'}; + char inDoubleStrs[10][20] = {{'\0'}}; + const int numDoubleVals = 10; + Bool result = swTRUE; char *MyFileName = InFiles[eMarkovCov]; - - if (NULL == (f = fopen(MyFileName, "r"))) { + f = OpenFile(MyFileName, "r", LogInfo); + if (LogInfo->stopRun) { return swFALSE; } @@ -654,23 +724,22 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { x = sscanf( inbuf, - "%d %f %f %f %f %f %f %f %f %f %f", - &week, - &t1, - &t2, - &t3, - &t4, - &t5, - &t6, - &cfxw, - &cfxd, - &cfnw, - &cfnd + "%2s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s", + weekStr, + inDoubleStrs[0], + inDoubleStrs[1], + inDoubleStrs[2], + inDoubleStrs[3], + inDoubleStrs[4], + inDoubleStrs[5], + inDoubleStrs[6], + inDoubleStrs[7], + inDoubleStrs[8], + inDoubleStrs[9] ); // Check that text file is ok: if (x < nitems) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -679,12 +748,27 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; + } + + week = sw_strtoi(weekStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + result = swFALSE; + goto closeFile; + } + + for (index = 0; index < numDoubleVals; index++) { + *(doubleVals[index]) = + sw_strtod(inDoubleStrs[index], MyFileName, LogInfo); + if (LogInfo->stopRun) { + result = swFALSE; + goto closeFile; + } } // week is a real calendar week if (!isfinite((float) week) || week < 1 || week > MAX_WEEKS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -694,12 +778,12 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Mean weekly temperature values are real numbers if (!isfinite(t1) || !isfinite(t2)) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -711,12 +795,12 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Covariance values are finite if (!isfinite(t3) || !isfinite(t4) || !isfinite(t5) || !isfinite(t6)) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -730,13 +814,13 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Correction factors are real numbers if (!isfinite(cfxw) || !isfinite(cfxd) || !isfinite(cfnw) || !isfinite(cfnd)) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -750,7 +834,8 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { lineno, MyFileName ); - return swFALSE; // Exit function prematurely due to error + result = swFALSE; + goto closeFile; } // Store values in `SW_Markov` @@ -778,20 +863,21 @@ Bool SW_MKV_read_cov(char *InFiles[], SW_MARKOV *SW_Markov, LOG_INFO *LogInfo) { SW_Markov->cfnd[week] = cfnd; } - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } - return swTRUE; + return result; } void SW_MKV_setup( SW_MARKOV *SW_Markov, unsigned long Weather_rng_seed, - int Weather_genWeathMethod, + unsigned int Weather_genWeathMethod, char *InFiles[], LOG_INFO *LogInfo ) { - Bool read_prob, read_cov; + Bool read_prob; + Bool read_cov; SW_MKV_construct(Weather_rng_seed, SW_Markov); allocateMKV(SW_Markov, LogInfo); diff --git a/src/SW_Model.c b/src/SW_Model.c index df5f3d7d2..e06feedac 100644 --- a/src/SW_Model.c +++ b/src/SW_Model.c @@ -47,7 +47,6 @@ #include "include/SW_Files.h" // for eModel #include "include/Times.h" // for Time_get_lastdoy_y, Time_init_model #include // for FILE -#include // for atof #include // for memcpy @@ -55,7 +54,7 @@ /* Local Variable */ /* --------------------------------------------------- */ -const TimeInt _notime = 0xffff; /* init value for _prev* */ +const TimeInt notime = 0xffff; /* init value for _prev* */ /* =================================================== */ /* Global Function Definitions */ @@ -115,8 +114,9 @@ void SW_MDL_read(SW_MODEL *SW_Model, char *InFiles[], LOG_INFO *LogInfo) { */ FILE *f; int lineno; - char *MyFileName, inbuf[MAX_FILENAMESIZE]; - double temp; + char *MyFileName; + char inbuf[MAX_FILENAMESIZE]; + double value; MyFileName = InFiles[eModel]; f = OpenFile(MyFileName, "r", LogInfo); @@ -131,31 +131,37 @@ void SW_MDL_read(SW_MODEL *SW_Model, char *InFiles[], LOG_INFO *LogInfo) { */ lineno = 0; while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { + if (lineno <= 4) { + value = sw_strtod(inbuf, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (lineno) { case 0: // Longitude // longitude is currently not used by the code, but may be used in // the future it is present in the `siteparam.in` input file to // completely document site location - SW_Model->longitude = atof(inbuf) * deg_to_rad; + SW_Model->longitude = value * deg_to_rad; break; case 1: // Latitude - SW_Model->latitude = atof(inbuf) * deg_to_rad; + SW_Model->latitude = value * deg_to_rad; // Calculate hemisphere based on latitude SW_Model->isnorth = (GT(SW_Model->latitude, 0.)) ? swTRUE : swFALSE; break; case 2: // Elevation - SW_Model->elevation = atof(inbuf); + SW_Model->elevation = value; break; case 3: // Slope - SW_Model->slope = atof(inbuf) * deg_to_rad; + SW_Model->slope = value * deg_to_rad; break; case 4: // Aspect - temp = atof(inbuf); - SW_Model->aspect = missing(temp) ? temp : temp * deg_to_rad; + SW_Model->aspect = missing(value) ? value : value * deg_to_rad; break; default: // More lines than expected @@ -165,14 +171,14 @@ void SW_MDL_read(SW_MODEL *SW_Model, char *InFiles[], LOG_INFO *LogInfo) { "More lines read than expected." "Please double check your `modelrun.in` file." ); - return; // Exit function prematurely due to error + goto closeFile; break; } lineno++; } - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -187,7 +193,7 @@ void SW_MDL_new_year(SW_MODEL *SW_Model) { */ TimeInt year = SW_Model->year; - SW_Model->_prevweek = SW_Model->_prevmonth = SW_Model->_prevyear = _notime; + SW_Model->prevweek = SW_Model->prevmonth = SW_Model->prevyear = notime; Time_new_year(year, SW_Model->days_in_month, SW_Model->cum_monthdays); SW_Model->simyear = SW_Model->year + SW_Model->addtl_yr; @@ -225,19 +231,19 @@ void SW_MDL_new_day(SW_MODEL *SW_Model) { return; } - if (SW_Model->month != SW_Model->_prevmonth) { + if (SW_Model->month != SW_Model->prevmonth) { SW_Model->newperiod[eSW_Month] = - (SW_Model->_prevmonth != _notime) ? swTRUE : swFALSE; - SW_Model->_prevmonth = SW_Model->month; + (SW_Model->prevmonth != notime) ? swTRUE : swFALSE; + SW_Model->prevmonth = SW_Model->month; } else { SW_Model->newperiod[eSW_Month] = swFALSE; } - /* if (SW_Model.week != _prevweek || SW_Model.month == NoMonth) { */ - if (SW_Model->week != SW_Model->_prevweek) { + /* if (SW_Model.week != prevweek || SW_Model.month == NoMonth) { */ + if (SW_Model->week != SW_Model->prevweek) { SW_Model->newperiod[eSW_Week] = - (SW_Model->_prevweek != _notime) ? swTRUE : swFALSE; - SW_Model->_prevweek = SW_Model->week; + (SW_Model->prevweek != notime) ? swTRUE : swFALSE; + SW_Model->prevweek = SW_Model->week; } else { SW_Model->newperiod[eSW_Week] = swFALSE; } diff --git a/src/SW_Output.c b/src/SW_Output.c index 9a06d57ec..b390f35e2 100644 --- a/src/SW_Output.c +++ b/src/SW_Output.c @@ -38,14 +38,13 @@ See the \ref out_algo "output algorithm documentation" for details. #include "include/SW_datastructs.h" // for SW_RUN, SW_OUTTEXT, LOG_INFO #include "include/SW_Defines.h" // for eSWC, OutPeriod, NVEGTYPES #include "include/SW_Files.h" // for eOutput, eSite -#include "include/SW_Site.h" // for _echo_inputs +#include "include/SW_Site.h" // for echo_inputs #include "include/SW_Times.h" // for Today, Yesterday -#include "include/SW_VegEstab.h" // for _echo_VegEstab -#include "include/SW_VegProd.h" // for _echo_VegProd +#include "include/SW_VegEstab.h" // for echo_VegEstab +#include "include/SW_VegProd.h" // for echo_VegProd #include "include/Times.h" // for Time_days_in_month, WKDAYS #include // for snprintf, fprintf, printf -#include // for atoi, free -#include // for strcat, strcmp, strcpy, memset +#include // for strcmp, memccpy, memset // Array-based output declarations: #if defined(SW_OUTARRAY) || defined(SWNETCDF) @@ -59,6 +58,7 @@ See the \ref out_algo "output algorithm documentation" for details. #if defined(SWNETCDF) #include "include/SW_netCDF.h" +#include // for free #endif /* Note: `get_XXX` functions are declared in `SW_Output.h` @@ -68,7 +68,7 @@ See the \ref out_algo "output algorithm documentation" for details. /* converts an enum output key (OutKey type) to a module */ /* or object type. see SW_Output.h for OutKey order. */ /* MUST be SW_OUTNKEYS of these */ -ObjType key2obj[] = { +const ObjType key2obj[] = { // weather/atmospheric quantities: eWTH, eWTH, @@ -115,7 +115,7 @@ ObjType key2obj[] = { // Convert from IDs to strings /* These MUST be in the same order as enum OutKey in * SW_Output.h */ -char const *key2str[] = { +const char *const key2str[] = { // weather/atmospheric quantities: SW_WETHR, SW_TEMP, @@ -154,15 +154,15 @@ char const *key2str[] = { SW_BIOMASS }; -char const *pd2str[] = {SW_DAY, SW_WEEK, SW_MONTH, SW_YEAR}; +const char *const pd2str[] = {SW_DAY, SW_WEEK, SW_MONTH, SW_YEAR}; -char const *pd2longstr[] = { +const char *const pd2longstr[] = { SW_DAY_LONG, SW_WEEK_LONG, SW_MONTH_LONG, SW_YEAR_LONG }; -char const *styp2str[] = {SW_SUM_OFF, SW_SUM_SUM, SW_SUM_AVG, SW_SUM_FNL}; +const char *const styp2str[] = {SW_SUM_OFF, SW_SUM_SUM, SW_SUM_AVG, SW_SUM_FNL}; -char const *styp2longstr[] = { +const char *const styp2longstr[] = { SW_SUM_OFF, SW_SUM_SUM, SW_SUM_AVG_LONG, SW_SUM_FNL_LONG }; @@ -216,7 +216,7 @@ static void average_for( ); #ifdef STEPWAT -static void _set_SXWrequests_helper( +static void set_SXWrequests_helper( SW_OUT_DOM *OutDom, OutKey k, OutPeriod pd, @@ -328,7 +328,7 @@ static void sumof_vpd( LOG_INFO *LogInfo ) { int ik; - RealD tmp; + double tmp; switch (k) { case eSW_CO2Effects: @@ -423,8 +423,8 @@ static void sumof_swc( ) { LyrIndex i; int j; // for use with ForEachVegType - LyrIndex n_layers = (LyrIndex) SW_Site->n_layers, - n_evap_layers = (LyrIndex) SW_Site->n_evap_lyrs; + LyrIndex n_layers = SW_Site->n_layers; + LyrIndex n_evap_layers = SW_Site->n_evap_lyrs; switch (k) { @@ -603,11 +603,12 @@ static void average_for( ) { TimeInt curr_pd = 0; - RealD div = 0.; /* if sumtype=AVG, days in period; if sumtype=SUM, 1 */ + double div = 0.; /* if sumtype=AVG, days in period; if sumtype=SUM, 1 */ LyrIndex i; - IntUS k; + int k; int j; - LyrIndex n_layers = sw->Site.n_layers, n_evap_layers = sw->Site.n_evap_lyrs; + LyrIndex n_layers = sw->Site.n_layers; + LyrIndex n_evap_layers = sw->Site.n_evap_lyrs; if (otyp == eVES) { return; @@ -938,10 +939,11 @@ static void average_for( sw->SoilWat.p_accu[pd]->snowdepth / div; break; - case eSW_Estab: /* do nothing, no averaging required */ - break; + case eSW_Estab: + /* do nothing, no averaging required */ case eSW_CO2Effects: + /* do nothing, no averaging required */ break; case eSW_Biomass: @@ -987,8 +989,10 @@ static void collect_sums( LOG_INFO *LogInfo ) { TimeInt pd = 0; - IntUS i, k; - Bool use_help, use_KeyPeriodCombo; + int i; + int k; + Bool use_help; + Bool use_KeyPeriodCombo; switch (op) { case eSW_Day: @@ -1090,7 +1094,7 @@ static void collect_sums( #ifdef STEPWAT -static void _set_SXWrequests_helper( +static void set_SXWrequests_helper( SW_OUT_DOM *OutDom, OutKey k, OutPeriod pd, @@ -1142,7 +1146,9 @@ static void _set_SXWrequests_helper( */ void find_OutPeriods_inUse(SW_OUT_DOM *OutDom) { OutPeriod p; - IntUS k, i, timeStepInd; + unsigned int k; + unsigned int i; + unsigned int timeStepInd; ForEachOutPeriod(p) { OutDom->use_OutPeriod[p] = swFALSE; } @@ -1219,7 +1225,7 @@ void SW_OUT_set_SXWrequests(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { OutDom->used_OUTNPERIODS = MAX(2, OutDom->used_OUTNPERIODS); // STEPWAT2 requires monthly summed transpiration - _set_SXWrequests_helper( + set_SXWrequests_helper( OutDom, eSW_Transp, eSW_Month, eSW_Sum, "monthly transpiration", LogInfo ); if (LogInfo->stopRun) { @@ -1227,7 +1233,7 @@ void SW_OUT_set_SXWrequests(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { } // STEPWAT2 requires monthly mean bulk soil water content - _set_SXWrequests_helper( + set_SXWrequests_helper( OutDom, eSW_SWCBulk, eSW_Month, @@ -1240,7 +1246,7 @@ void SW_OUT_set_SXWrequests(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { } // STEPWAT2 requires annual and monthly mean air temperature - _set_SXWrequests_helper( + set_SXWrequests_helper( OutDom, eSW_Temp, eSW_Month, @@ -1254,7 +1260,7 @@ void SW_OUT_set_SXWrequests(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { OutDom->timeSteps_SXW[eSW_Temp][1] = eSW_Year; // STEPWAT2 requires annual and monthly precipitation sum - _set_SXWrequests_helper( + set_SXWrequests_helper( OutDom, eSW_Precip, eSW_Month, @@ -1268,7 +1274,7 @@ void SW_OUT_set_SXWrequests(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { OutDom->timeSteps_SXW[eSW_Precip][1] = eSW_Year; // STEPWAT2 requires annual sum of AET - _set_SXWrequests_helper( + set_SXWrequests_helper( OutDom, eSW_AET, eSW_Year, eSW_Sum, "annual AET", LogInfo ); if (LogInfo->stopRun) { @@ -1286,7 +1292,8 @@ void SW_OUT_set_SXWrequests(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { void SW_OUT_init_ptrs(SW_OUT_RUN *OutRun) { #if defined(SW_OUTARRAY) - IntUS key, column; + int key; + int column; ForEachOutKey(key) { for (column = 0; column < SW_OUTNPERIODS; column++) { OutRun->p_OUT[key][column] = NULL; @@ -1301,7 +1308,8 @@ void SW_OUT_init_ptrs(SW_OUT_RUN *OutRun) { } void SW_OUTDOM_init_ptrs(SW_OUT_DOM *OutDom) { - IntUS key, column; + int key; + int column; ForEachOutKey(key) { for (column = 0; column < 5 * NVEGTYPES + MAX_LAYERS; column++) { @@ -1332,7 +1340,7 @@ void SW_OUTDOM_init_ptrs(SW_OUT_DOM *OutDom) { */ void SW_OUTDOM_construct(SW_OUT_DOM *OutDom) { - IntUS k; + int k; OutPeriod p; memset(OutDom, 0, sizeof(SW_OUT_DOM)); @@ -1839,18 +1847,13 @@ void SW_OUTDOM_construct(SW_OUT_DOM *OutDom) { void SW_OUT_construct( Bool zeroOutStruct, - Bool make_soil[], - Bool make_regular[], + SW_FILE_STATUS *FileStatus, SW_OUT_DOM *OutDom, SW_OUT_RUN *OutRun, - LyrIndex n_layers, LOG_INFO *LogInfo ) { /* =================================================== */ - LyrIndex i; OutPeriod p; - SW_SOILWAT_OUTPUTS *s = NULL; - int j; if (zeroOutStruct) { memset(OutRun, 0, sizeof(SW_OUT_RUN)); @@ -1858,19 +1861,14 @@ void SW_OUT_construct( #if defined(SW_OUTTEXT) ForEachOutPeriod(p) { - make_soil[p] = swFALSE; - make_regular[p] = swFALSE; + FileStatus->make_soil[p] = swFALSE; + FileStatus->make_regular[p] = swFALSE; } #else /* Silence compiler */ - (void) make_soil; - (void) make_regular; + (void) FileStatus; #endif - ForEachSoilLayer(i, n_layers) { - ForEachVegType(j) { s->SWA_VegType[j][i] = 0.; } - } - #if defined(SW_OUTARRAY) ForEachOutPeriod(p) { OutRun->irow_OUT[p] = 0; } #else @@ -1902,12 +1900,13 @@ void SW_OUT_deconstruct(Bool full_reset, SW_RUN *sw) { #if defined(SWNETCDF) OutPeriod pd; - IntUS k; + unsigned int k; + unsigned int file; ForEachOutKey(k) { ForEachOutPeriod(pd) { if (!isnull(sw->FileStatus.ncOutFiles[k][pd])) { - for (int file = 0; file < sw->FileStatus.numOutFiles; file++) { + for (file = 0; file < sw->FileStatus.numOutFiles; file++) { if (!isnull(sw->FileStatus.ncOutFiles[k][pd][file])) { free(sw->FileStatus.ncOutFiles[k][pd][file]); @@ -1915,12 +1914,12 @@ void SW_OUT_deconstruct(Bool full_reset, SW_RUN *sw) { } } - free(sw->FileStatus.ncOutFiles[k][pd]); + free((void *) sw->FileStatus.ncOutFiles[k][pd]); sw->FileStatus.ncOutFiles[k][pd] = NULL; } if (!isnull(sw->FileStatus.ncOutFiles[k][pd])) { - free(sw->FileStatus.ncOutFiles[k][pd]); + free((void *) sw->FileStatus.ncOutFiles[k][pd]); sw->FileStatus.ncOutFiles[k][pd] = NULL; } } @@ -1946,16 +1945,17 @@ Note to programmer: this function must match what `get_*()` implement. as array of size SW_OUTNKEYS by SW_OUTNMAXVARS. */ void SW_OUT_set_ncol( - int tLayers, - int n_evap_lyrs, - int nTaxaEstabl, + unsigned int tLayers, + unsigned int n_evap_lyrs, + unsigned int nTaxaEstabl, IntUS ncol_OUT[], IntUS nvar_OUT[], IntUS nsl_OUT[][SW_OUTNMAXVARS], IntUS npft_OUT[][SW_OUTNMAXVARS] ) { - int key, ivar; + unsigned int key; + unsigned int ivar; IntUS tmp; //--- Set number of output variables ------ @@ -2108,17 +2108,18 @@ Ck_Lyr1, ..., Ck_LyrN` @sideeffect Set values of colnames_OUT */ void SW_OUT_set_colnames( - int tLayers, + unsigned int tLayers, SW_VEGESTAB_INFO **parms, - IntUS ncol_OUT[], + const IntUS ncol_OUT[], char *colnames_OUT[][5 * NVEGTYPES + MAX_LAYERS], LOG_INFO *LogInfo ) { - IntUS i, j; #ifdef SWDEBUG int debug = 0; #endif + unsigned int i; + unsigned int j; char ctemp[50]; const char *Layers_names[MAX_LAYERS] = { "Lyr_1", "Lyr_2", "Lyr_3", "Lyr_4", "Lyr_5", "Lyr_6", "Lyr_7", @@ -2160,12 +2161,18 @@ void SW_OUT_set_colnames( for (i = 0; i < ncol_OUT[eSW_Temp]; i++) { if (i < 3) { // Normal air temperature columns - strcpy(ctemp, cnames_eSW_Temp[i]); + (void) sw_memccpy( + ctemp, (char *) cnames_eSW_Temp[i], '\0', sizeof ctemp + ); } else { // Surface temperature columns - strcpy(ctemp, cnames_eSW_Temp[3]); - strcat(ctemp, "_"); - strcat(ctemp, cnames_eSW_Temp[i % 3]); + (void) snprintf( + ctemp, + sizeof ctemp, + "%s_%s", + cnames_eSW_Temp[3], + cnames_eSW_Temp[i % 3] + ); } colnames_OUT[eSW_Temp][i] = Str_Dup(ctemp, LogInfo); @@ -2190,6 +2197,7 @@ void SW_OUT_set_colnames( } #endif for (i = 0; i < ncol_OUT[eSW_SoilInf]; i++) { + // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage) colnames_OUT[eSW_SoilInf][i] = Str_Dup(cnames_eSW_SoilInf[i], LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2257,13 +2265,13 @@ void SW_OUT_set_colnames( #endif for (i = 0; i < tLayers; i++) { for (j = 0; j < NVEGTYPES; j++) { - strcpy(ctemp, "swa_"); - strcat( - ctemp, cnames_VegTypes[j + 1] - ); // j+1 since no total column for swa. - strcat(ctemp, "_"); - strcat(ctemp, Layers_names[i]); - + (void) snprintf( + ctemp, + sizeof ctemp, + "swa_%s_%s", + cnames_VegTypes[j + 1], // j+1 since no total column for swa. + Layers_names[i] + ); colnames_OUT[eSW_SWA][i + j * tLayers] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2298,8 +2306,10 @@ void SW_OUT_set_colnames( } #endif for (i = 0; i < ncol_OUT[eSW_SurfaceWater]; i++) { + // NOLINTBEGIN(clang-analyzer-core.CallAndMessage) colnames_OUT[eSW_SurfaceWater][i] = Str_Dup(cnames_eSW_SurfaceWater[i], LogInfo); + // NOLINTEND(clang-analyzer-core.CallAndMessage) if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -2311,11 +2321,13 @@ void SW_OUT_set_colnames( #endif for (i = 0; i < tLayers; i++) { for (j = 0; j < NVEGTYPES + 1; j++) { - strcpy(ctemp, "transp_"); - strcat(ctemp, cnames_VegTypes[j]); - strcat(ctemp, "_"); - strcat(ctemp, Layers_names[i]); - + (void) snprintf( + ctemp, + sizeof ctemp, + "transp_%s_%s", + cnames_VegTypes[j], + Layers_names[i] + ); colnames_OUT[eSW_Transp][i + j * tLayers] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2339,16 +2351,15 @@ void SW_OUT_set_colnames( } #endif for (i = 0; i < NVEGTYPES + 2; i++) { - strcpy(ctemp, "evap_"); - strcat(ctemp, cnames_VegTypes[i]); + (void) snprintf(ctemp, sizeof ctemp, "evap_%s", cnames_VegTypes[i]); colnames_OUT[eSW_EvapSurface][i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } } - for (i = 0; i < ncol_OUT[eSW_EvapSurface] - (NVEGTYPES + 2); i++) { - colnames_OUT[eSW_EvapSurface][NVEGTYPES + 2 + i] = - Str_Dup(cnames_add_eSW_EvapSurface[i], LogInfo); + for (i = NVEGTYPES + 2; i < ncol_OUT[eSW_EvapSurface]; i++) { + colnames_OUT[eSW_EvapSurface][i] = + Str_Dup(cnames_add_eSW_EvapSurface[i - (NVEGTYPES + 2)], LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -2359,8 +2370,7 @@ void SW_OUT_set_colnames( } #endif for (i = 0; i < NVEGTYPES + 2; i++) { - strcpy(ctemp, "int_"); - strcat(ctemp, cnames_VegTypes[i]); + (void) snprintf(ctemp, sizeof ctemp, "int_%s", cnames_VegTypes[i]); colnames_OUT[eSW_Interception][i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2384,9 +2394,13 @@ void SW_OUT_set_colnames( #endif for (i = 0; i < tLayers; i++) { for (j = 0; j < NVEGTYPES + 1; j++) { - strcpy(ctemp, cnames_VegTypes[j]); - strcat(ctemp, "_"); - strcat(ctemp, Layers_names[i]); + (void) snprintf( + ctemp, + sizeof ctemp, + "%s_%s", + cnames_VegTypes[j], + Layers_names[i] + ); colnames_OUT[eSW_HydRed][i + j * tLayers] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2464,10 +2478,13 @@ void SW_OUT_set_colnames( } // For layers 1 through ncol_OUT[eSW_SoilTemp] - strcpy(ctemp, Layers_names[j]); - - strcat(ctemp, "_"); - strcat(ctemp, cnames_eSW_Temp[i % 3]); + (void) snprintf( + ctemp, + sizeof ctemp, + "%s_%s", + Layers_names[j], + cnames_eSW_Temp[i % 3] + ); colnames_OUT[eSW_SoilTemp][i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { @@ -2504,9 +2521,13 @@ void SW_OUT_set_colnames( #endif for (i = 0; i < 2; i++) { for (j = 0; j < NVEGTYPES; j++) { - strcpy(ctemp, cnames_eSW_CO2Effects[i]); - strcat(ctemp, "_"); - strcat(ctemp, cnames_VegTypes[j + 1]); // j+1 since no total column + (void) snprintf( + ctemp, + sizeof ctemp, + "%s_%s", + cnames_eSW_CO2Effects[i], + cnames_VegTypes[j + 1] // j+1 since no total column + ); colnames_OUT[eSW_CO2Effects][j + i * NVEGTYPES] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { @@ -2521,15 +2542,19 @@ void SW_OUT_set_colnames( } #endif i = 0; - strcpy(ctemp, "fCover_BareGround"); + (void) sw_memccpy(ctemp, "fCover_BareGround", '\0', sizeof ctemp); colnames_OUT[eSW_Biomass][i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } i = 1; for (j = 0; j < NVEGTYPES; j++) { - strcpy(ctemp, "fCover_"); - strcat(ctemp, cnames_VegTypes[j + 1]); // j+1 since no total column + (void) snprintf( + ctemp, + sizeof ctemp, + "fCover_%s", + cnames_VegTypes[j + 1] // j+1 since no total column + ); colnames_OUT[eSW_Biomass][j + i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2537,8 +2562,7 @@ void SW_OUT_set_colnames( } i += j; for (j = 0; j < NVEGTYPES + 2; j++) { - strcpy(ctemp, "Biomass_"); - strcat(ctemp, cnames_VegTypes[j]); + (void) snprintf(ctemp, sizeof ctemp, "Biomass_%s", cnames_VegTypes[j]); colnames_OUT[eSW_Biomass][j + i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -2546,15 +2570,14 @@ void SW_OUT_set_colnames( } i += j; for (j = 0; j < NVEGTYPES + 1; j++) { - strcpy(ctemp, "Biolive_"); - strcat(ctemp, cnames_VegTypes[j]); + (void) snprintf(ctemp, sizeof ctemp, "Biolive_%s", cnames_VegTypes[j]); colnames_OUT[eSW_Biomass][j + i] = Str_Dup(ctemp, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } } i += j; - strcpy(ctemp, "LAI_total"); + (void) snprintf(ctemp, sizeof ctemp, "%s", "LAI_total"); colnames_OUT[eSW_Biomass][i] = Str_Dup(ctemp, LogInfo); #ifdef SWDEBUG @@ -2578,8 +2601,8 @@ void SW_OUT_set_colnames( @param[out] LogInfo Holds information on warnings and errors */ void SW_OUT_setup_output( - int tLayers, - int n_evap_lyrs, + unsigned int tLayers, + unsigned int n_evap_lyrs, SW_VEGESTAB *SW_VegEstab, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo @@ -2625,7 +2648,7 @@ void SW_OUT_new_year( /* =================================================== */ /* reset the terminal output days each year */ - IntUS k; + int k; ForEachOutKey(k) { if (!OutDom->use[k]) { @@ -2677,7 +2700,7 @@ int SW_OUT_read_onekey( if (OutDom->sumtype[k] == eSW_Fnl && !OutDom->has_sl[k]) { OutDom->sumtype[k] = eSW_Avg; - snprintf( + (void) snprintf( msg, sizeof_msg, "%s : Summary Type FIN with key %s is meaningless.\n" @@ -2706,7 +2729,7 @@ int SW_OUT_read_onekey( k == eSW_AllH2O)) { OutDom->use[k] = swFALSE; - snprintf( + (void) snprintf( msg, sizeof_msg, "%s : Output key %s is currently unimplemented.", @@ -2720,7 +2743,7 @@ int SW_OUT_read_onekey( if (k == eSW_DeepSWC && OutDom->sumtype[k] != eSW_Off && !deepdrain) { OutDom->use[k] = swFALSE; - snprintf( + (void) snprintf( msg, sizeof_msg, "%s : DEEPSWC cannot produce output if deep drainage is " @@ -2736,7 +2759,7 @@ int SW_OUT_read_onekey( OutDom->last_orig[k] = last; if (OutDom->last_orig[k] == 0) { - snprintf( + (void) snprintf( msg, sizeof_msg, "%s : Invalid ending day (%d), key=%s.", @@ -2786,9 +2809,12 @@ void SW_OUT_read( * In fact, the only keys to process are * TRANSP, PRECIP, and TEMP. */ + FILE *f; - OutKey k; - int x, itemno, msg_type; + OutKey k = eSW_NoKey; + int x; + int itemno; + int msg_type; IntUS i; Bool useTimeStep = swFALSE; IntUS *used_OUTNPERIODS = &OutDom->used_OUTNPERIODS; @@ -2797,20 +2823,24 @@ void SW_OUT_read( /* except for the uppercase space. */ // timeStep: matrix to capture all the periods entered in outsetup.in char timeStep[SW_OUTNPERIODS][10]; - char keyname[50], ext[10]; + char keyname[50]; + char ext[10]; /* sumtype: should be 2 chars, but we don't want overflow from user typos */ char sumtype[4]; char period[10 /* last: last doy for output, if "end", ==366 */]; - char last[4]; + char lastStr[4]; + char firstStr[4]; char outfile[MAX_FILENAMESIZE]; // message to print char msg[200]; /* space for uppercase conversion */ - char upkey[50], upsum[4]; + char upkey[50]; + char upsum[4]; char inbuf[MAX_FILENAMESIZE]; - int first; /* first doy for output */ + int first; + int last = -1; /* first doy for output */ char *MyFileName = InFiles[eOutput]; f = OpenFile(MyFileName, "r", LogInfo); @@ -2829,12 +2859,12 @@ void SW_OUT_read( x = sscanf( inbuf, - "%s %s %s %d %s %s", + "%s %s %s %3s %3s %s", keyname, sumtype, period, - &first, - last, + firstStr, + lastStr, outfile ); @@ -2848,7 +2878,7 @@ void SW_OUT_read( // maximum number of possible timeStep is SW_OUTNPERIODS *used_OUTNPERIODS = sscanf( inbuf, - "%s %s %s %s %s", + "%9s %9s %9s %9s %9s", keyname, timeStep[0], timeStep[1], @@ -2866,7 +2896,6 @@ void SW_OUT_read( useTimeStep = swTRUE; if (*used_OUTNPERIODS > SW_OUTNPERIODS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -2875,7 +2904,7 @@ void SW_OUT_read( *used_OUTNPERIODS, SW_OUTNPERIODS ); - return; // Exit function prematurely due to error + goto closeFile; } } @@ -2899,7 +2928,6 @@ void SW_OUT_read( // we have read a line that specifies an output key/type // make sure that we got enough input if (x < 6) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -2908,36 +2936,45 @@ void SW_OUT_read( keyname, itemno ); - return; // Exit function prematurely due to error - } - - // Convert strings to index numbers - k = str2key(Str_ToUpper(keyname, upkey), LogInfo); - if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } // For now: rSOILWAT2's function `onGet_SW_OUT` requires that // `OutDom->outfile[k]` is allocated here #if defined(RSOILWAT) - OutDom->outfile[k] = (char *) Str_Dup(outfile, LogInfo); + OutDom->outfile[k] = Str_Dup(outfile, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } #else outfile[0] = '\0'; #endif + first = sw_strtoi(firstStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + + if (Str_CompareI(lastStr, (char *) "END") != 0) { + last = sw_strtoi(lastStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + + // Convert strings to index numbers + k = str2key(Str_ToUpper(keyname, upkey), LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + // Fill information into `sw->Output[k]` msg_type = SW_OUT_read_onekey( OutDom, k, str2stype(Str_ToUpper(sumtype, upsum), LogInfo), first, - (Str_CompareI((char *) last, (char *) "END") == 0) ? 366 : - atoi(last), + (Str_CompareI(lastStr, (char *) "END") == 0) ? 366 : last, msg, sizeof msg, &sw->VegProd.use_SWA, @@ -2949,8 +2986,7 @@ void SW_OUT_read( LogError(LogInfo, msg_type, "%s", msg); if (msg_type == LOGERROR) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } } @@ -2971,8 +3007,6 @@ void SW_OUT_read( } } // end of while-loop - CloseFile(&f, LogInfo); - // Determine which output periods are turned on for at least one output key find_OutPeriods_inUse(OutDom); @@ -2992,9 +3026,11 @@ void SW_OUT_read( // Determine number of used years/months/weeks/days in simulation period SW_OUT_set_nrow(&sw->Model, OutDom->use_OutPeriod, OutDom->nrow_OUT); #endif + +closeFile: { CloseFile(&f, LogInfo); } } -void _collect_values( +void collect_values( SW_RUN *sw, SW_OUT_DOM *OutDom, Bool bFlush_output, @@ -3022,7 +3058,7 @@ void _collect_values( return; // Exit function prematurely due to error } - SW_OUT_write_today(sw, OutDom, bFlush_output, tOffset); + SW_OUT_write_today(sw, OutDom, bFlush_output, tOffset, LogInfo); } /** called at year end to process the remainder of the output period. @@ -3039,7 +3075,7 @@ subs. void SW_OUT_flush(SW_RUN *sw, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { TimeInt localTOffset = 0; // tOffset is zero when called from this function - _collect_values(sw, OutDom, swTRUE, localTOffset, LogInfo); + collect_values(sw, OutDom, swTRUE, localTOffset, LogInfo); } /** adds today's output values to week, month and year @@ -3119,7 +3155,7 @@ void SW_OUT_sum_today( /** `SW_OUT_write_today` is called twice - - `_end_day` at the end of each day with values + - `end_day` at the end of each day with values values of `bFlush_output` set to FALSE and `tOffset` set to 1 - `SW_OUT_flush` at the end of every year with values of `bFlush_output` set to TRUE and `tOffset` set to 0 @@ -3131,9 +3167,14 @@ void SW_OUT_sum_today( @param[in] bFlush_output Determines if output should be created for a specific output key @param[in] tOffset Offset describing with the previous or current period +@param[out] LogInfo Holds information on warnings and errors */ void SW_OUT_write_today( - SW_RUN *sw, SW_OUT_DOM *OutDom, Bool bFlush_output, TimeInt tOffset + SW_RUN *sw, + SW_OUT_DOM *OutDom, + Bool bFlush_output, + TimeInt tOffset, + LOG_INFO *LogInfo ) { /* --------------------------------------------------- */ /* all output values must have been summed, averaged or @@ -3160,26 +3201,62 @@ void SW_OUT_write_today( * July 12, 2017: Added functionality for writing outputs for STEPPE and * SOILWAT since we now want output for STEPPE */ +#ifdef SWDEBUG + int debug = 0; +#endif + TimeInt t = 0xffff; OutPeriod p; - Bool writeit[SW_OUTNPERIODS], use_help; + Bool writeit[SW_OUTNPERIODS]; + Bool use_help; // Temporary string to hold sw_outstr before concatenating // to buf_soil/buf_reg // Silences -Wrestrict when compiling on Linux (found within -Wall) char tempstr[MAX_LAYERS * OUTSTRLEN]; + int k; + int i; + int outPeriod; + +#ifdef SW_OUTTEXT + char *resPtr = NULL; + + char *soilWritePtr[SW_OUTNPERIODS] = { + sw->FileStatus.buf_soil[0], + sw->FileStatus.buf_soil[1], + sw->FileStatus.buf_soil[2], + sw->FileStatus.buf_soil[3] + }; + char *regWritePtr[SW_OUTNPERIODS] = { + sw->FileStatus.buf_reg[0], + sw->FileStatus.buf_reg[1], + sw->FileStatus.buf_reg[2], + sw->FileStatus.buf_reg[3] + }; +#endif + #ifdef STEPWAT - Bool use_help_txt, use_help_SXW; + Bool use_help_txt; + Bool use_help_SXW; + + char *soilAggWritePtr[SW_OUTNPERIODS] = { + sw->FileStatus.buf_soil[0], + sw->FileStatus.buf_soil[1], + sw->FileStatus.buf_soil[2], + sw->FileStatus.buf_soil[3] + }; + char *regAggWritePtr[SW_OUTNPERIODS] = { + sw->FileStatus.buf_reg[0], + sw->FileStatus.buf_reg[1], + sw->FileStatus.buf_reg[2], + sw->FileStatus.buf_reg[3] + }; #endif - IntUS k, i, outPeriod; + /* Update `tOffset` within SW_OUT_RUN for output functions */ sw->OutRun.tOffset = tOffset; -#ifdef SWDEBUG - int debug = 0; -#endif - #if defined(SW_OUTTEXT) char str_time[10]; // year and day/week/month header for each output row @@ -3193,6 +3270,8 @@ void SW_OUT_write_today( sw->FileStatus.buf_soil_agg[p][0] = '\0'; #endif } +#else + (void) LogInfo; #endif #ifdef SWDEBUG @@ -3225,7 +3304,7 @@ void SW_OUT_write_today( writeit[eSW_Year] = (Bool) (sw->Model.newperiod[eSW_Year] || bFlush_output); // update daily: don't process daily output if `bFlush_output` is TRUE - // because `_end_day` was already called and produced daily output + // because `end_day` was already called and produced daily output writeit[eSW_Day] = (Bool) (writeit[eSW_Day] && !bFlush_output); @@ -3233,6 +3312,37 @@ void SW_OUT_write_today( // formatting functions `get_XXX`, and concatenate for one row of // `csv`-output ForEachOutKey(k) { +#ifdef SW_OUTTEXT + size_t writeSizeReg[SW_OUTNPERIODS] = { + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN) + }; + + size_t writeSizeSoil[SW_OUTNPERIODS] = { + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN) + }; +#endif + +#ifdef STEPWAT + size_t writeSizeSoilAgg[SW_OUTNPERIODS] = { + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN) + }; + size_t writeSizeRegAgg[SW_OUTNPERIODS] = { + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN), + (size_t) (MAX_LAYERS * OUTSTRLEN) + }; +#endif + #ifdef SWDEBUG if (debug) { sw_printf("key=%d=%s: ", k, key2str[k]); @@ -3244,6 +3354,7 @@ void SW_OUT_write_today( } for (i = 0; i < OutDom->used_OUTNPERIODS; i++) { + outPeriod = OutDom->timeSteps[k][i]; use_help = (Bool) (outPeriod != eSW_NoTime && writeit[outPeriod]); @@ -3266,9 +3377,7 @@ void SW_OUT_write_today( ); } #endif - - ((void (*)(OutPeriod, SW_RUN *) - ) OutDom->pfunc_text[k])(outPeriod, sw); + OutDom->pfunc_text[k](outPeriod, sw); #elif defined(RSOILWAT) || defined(SWNETCDF) #ifdef SWDEBUG @@ -3278,8 +3387,7 @@ void SW_OUT_write_today( ); } #endif - ((void (*)(OutPeriod, SW_RUN *, SW_OUT_DOM *) - ) OutDom->pfunc_mem[k])(outPeriod, sw, OutDom); + OutDom->pfunc_mem[k](outPeriod, sw, OutDom); #elif defined(STEPWAT) if (use_help_SXW) { @@ -3292,43 +3400,34 @@ void SW_OUT_write_today( ); } #endif - ((void (*)(OutPeriod, SW_RUN *, SW_OUT_DOM *) - ) OutDom->pfunc_SXW[k])( - OutDom->timeSteps_SXW[k][i], sw, OutDom - ); + OutDom->pfunc_SXW[k](OutDom->timeSteps_SXW[k][i], sw, OutDom); } if (!use_help_txt) { continue; // SXW output complete; skip to next output period - } else { - if (OutDom->prepare_IterationSummary) { + } + + if (OutDom->prepare_IterationSummary) { #ifdef SWDEBUG - if (debug) { - sw_printf( - " call pfunc_agg(%d=%s))", - outPeriod, - pd2str[outPeriod] - ); - } -#endif - ((void (*)(OutPeriod, SW_RUN *, SW_OUT_DOM *) - ) OutDom->pfunc_agg[k])(outPeriod, sw, OutDom); + if (debug) { + sw_printf( + " call pfunc_agg(%d=%s))", outPeriod, pd2str[outPeriod] + ); } +#endif + OutDom->pfunc_agg[k](outPeriod, sw, OutDom); + } - if (OutDom->print_SW_Output) { - outPeriod = OutDom->timeSteps[k][i]; + if (OutDom->print_SW_Output) { + outPeriod = OutDom->timeSteps[k][i]; #ifdef SWDEBUG - if (debug) { - sw_printf( - " call pfunc_text(%d=%s))", - outPeriod, - pd2str[outPeriod] - ); - } -#endif - ((void (*)(OutPeriod, SW_RUN *) - ) OutDom->pfunc_text[k])(outPeriod, sw); + if (debug) { + sw_printf( + " call pfunc_text(%d=%s))", outPeriod, pd2str[outPeriod] + ); } +#endif + OutDom->pfunc_text[k](outPeriod, sw); } #endif @@ -3341,21 +3440,66 @@ void SW_OUT_write_today( #if defined(SW_OUTTEXT) /* concatenate formatted output for one row of `csv`- files */ if (OutDom->print_SW_Output) { - strcpy(tempstr, sw->OutRun.sw_outstr); + (void) sw_memccpy( + tempstr, + sw->OutRun.sw_outstr, + '\0', + (size_t) (MAX_LAYERS * OUTSTRLEN) + ); + if (OutDom->has_sl[k]) { - strcat(sw->FileStatus.buf_soil[outPeriod], tempstr); + resPtr = (char *) sw_memccpy( + soilWritePtr[outPeriod], + tempstr, + '\0', + writeSizeSoil[outPeriod] + ); + soilWritePtr[outPeriod] = resPtr - 1; + writeSizeSoil[outPeriod] -= + (resPtr - soilWritePtr[outPeriod] - 1); } else { - strcat(sw->FileStatus.buf_reg[outPeriod], tempstr); + resPtr = (char *) sw_memccpy( + regWritePtr[outPeriod], + tempstr, + '\0', + writeSizeReg[outPeriod] + ); + regWritePtr[outPeriod] = resPtr - 1; + writeSizeReg[outPeriod] -= + (resPtr - regWritePtr[outPeriod] - 1); } } + #ifdef STEPWAT if (OutDom->print_IterationSummary) { - strcpy(tempstr, sw->OutRun.sw_outstr_agg); + (void) sw_memccpy( + tempstr, + sw->OutRun.sw_outstr_agg, + '\0', + (size_t) (MAX_LAYERS * OUTSTRLEN) + ); + if (OutDom->has_sl[k]) { - strcat(sw->FileStatus.buf_soil_agg[outPeriod], tempstr); + resPtr = sw_memccpy( + soilAggWritePtr[outPeriod], + tempstr, + '\0', + writeSizeSoilAgg[outPeriod] + ); + soilAggWritePtr[outPeriod] = resPtr - 1; + writeSizeSoilAgg[outPeriod] -= + (resPtr - soilAggWritePtr[outPeriod] - 1); } else { - strcat(sw->FileStatus.buf_reg_agg[outPeriod], tempstr); + resPtr = sw_memccpy( + regAggWritePtr[outPeriod], + tempstr, + '\0', + writeSizeRegAgg[outPeriod] + ); + regAggWritePtr[outPeriod] = resPtr - 1; + writeSizeRegAgg[outPeriod] -= + (resPtr - regAggWritePtr[outPeriod] - 1); } } #endif @@ -3366,6 +3510,8 @@ void SW_OUT_write_today( } // end of loop across output keys #if defined(SW_OUTTEXT) + int fprintRes = 0; + // write formatted output to csv-files ForEachOutPeriod(p) { if (OutDom->use_OutPeriod[p] && writeit[p]) { @@ -3373,48 +3519,94 @@ void SW_OUT_write_today( if (sw->FileStatus.make_regular[p]) { if (OutDom->print_SW_Output) { - fprintf( + fprintRes = fprintf( sw->FileStatus.fp_reg[p], "%s%s\n", str_time, sw->FileStatus.buf_reg[p] ); + + if (fprintRes < 0) { + LogError( + LogInfo, + LOGERROR, + "Could not write values to \"regular\" CSVs." + ); + return; /* Exit prematurely due to error */ + } + // STEPWAT2 needs a fflush for yearly output; // other time steps, the soil-layer files, and SOILWAT2 work // fine without it... - fflush(sw->FileStatus.fp_reg[p]); + if (fflush(sw->FileStatus.fp_reg[p]) == EOF) { + LogError( + LogInfo, + LOGERROR, + "Could not write flush values to \"regular\" CSVs." + ); + return; /* Exit prematurely due to error */ + } } #ifdef STEPWAT if (OutDom->print_IterationSummary) { - fprintf( + fprintRes = fprintf( sw->FileStatus.fp_reg_agg[p], "%s%s\n", str_time, sw->FileStatus.buf_reg_agg[p] ); + + if (fprintRes < 0) { + LogError( + LogInfo, + LOGERROR, + "Could not write values to \"regular\" aggregation " + "iteration files." + ); + return; /* Exit prematurely due to error */ + } } #endif } if (sw->FileStatus.make_soil[p]) { if (OutDom->print_SW_Output) { - fprintf( + fprintRes = fprintf( sw->FileStatus.fp_soil[p], "%s%s\n", str_time, sw->FileStatus.buf_soil[p] ); + + if (fprintRes < 0) { + LogError( + LogInfo, + LOGERROR, + "Could not write values to \"soil\" output files." + ); + return; /* Exit prematurely due to error */ + } } #ifdef STEPWAT if (OutDom->print_IterationSummary) { - fprintf( + fprintRes = fprintf( sw->FileStatus.fp_soil_agg[p], "%s%s\n", str_time, sw->FileStatus.buf_soil_agg[p] ); + + if (fprintRes < 0) { + LogError( + LogInfo, + LOGERROR, + "Could not write values to \"soil\" aggregation " + "iteration files." + ); + return; /* Exit prematurely due to error */ + } } #endif } @@ -3522,45 +3714,87 @@ void SW_OUT_close_files( #endif } -void _echo_outputs(SW_OUT_DOM *OutDom) { - IntUS k; - char str[OUTSTRLEN], errstr[MAX_ERROR]; - - strcpy( - errstr, +void echo_outputs(SW_OUT_DOM *OutDom) { + int k; + int index; + int writeValIndex = 0; + char str[OUTSTRLEN]; + char errstr[MAX_ERROR]; + size_t writeSize = MAX_ERROR; + char *writePtr = errstr; + char *resPtr = NULL; + char *cpyPtr = NULL; + const int numWriteStrs = 6; + const size_t errHeaderSize = 75; + + const char *errStrHeader = "---------------------------\nKey "; + + const char *errStrFooter = + "\n---------- End of Output Configuration ---------- \n"; + + const char *errStrConf = "\n===============================================\n" - " Output Configuration:\n" - ); + " Output Configuration:\n"; + + char *writeStrs[] = { + (char *) errStrHeader, + (char *) key2str[0], /* Overwrite in loop below */ + (char *) "\n\tSummary Type: ", + (char *) styp2str[0], /* Overwrite in loop below */ + (char *) "\n\tStart period: %d", + (char *) "\n\tEnd period : %d\n" + }; + + TimeInt writeVals[] = { + OutDom->first_orig[0], /* Overwrite in loop below */ + OutDom->last_orig[0] /* Overwrite in loop below */ + }; + + (void) sw_memccpy(errstr, (char *) errStrConf, '\0', errHeaderSize); + ForEachOutKey(k) { - if (!OutDom->use[k]) { + if (OutDom->use[k]) { + writeStrs[1] = (char *) key2str[k]; + writeStrs[3] = (char *) styp2str[OutDom->sumtype[k]]; + + writeVals[0] = OutDom->first_orig[k]; + writeVals[0] = OutDom->last_orig[k]; + } else { continue; } - strcat(errstr, "---------------------------\nKey "); - strcat(errstr, key2str[k]); - strcat(errstr, "\n\tSummary Type: "); - strcat(errstr, styp2str[OutDom->sumtype[k]]); - snprintf(str, OUTSTRLEN, "\n\tStart period: %d", OutDom->first_orig[k]); - strcat(errstr, str); - snprintf(str, OUTSTRLEN, "\n\tEnd period : %d", OutDom->last_orig[k]); - strcat(errstr, str); - strcat(errstr, "\n"); + + for (index = 0; index < numWriteStrs; index++) { + cpyPtr = writeStrs[index]; + + if (index > 4) { + (void + ) snprintf(str, OUTSTRLEN, cpyPtr, writeVals[writeValIndex]); + + writeValIndex++; + cpyPtr = str; + } + + resPtr = (char *) sw_memccpy(writePtr, cpyPtr, '\0', writeSize); + writeSize -= (resPtr - writePtr - 1); + writePtr = resPtr - 1; + } } - strcat(errstr, "\n---------- End of Output Configuration ---------- \n"); + sw_memccpy(writePtr, (char *) errStrFooter, '\0', writeSize); printf("%s\n", errstr); } -void _echo_all_inputs(SW_RUN *sw, SW_OUT_DOM *OutDom) { +void echo_all_inputs(SW_RUN *sw, SW_OUT_DOM *OutDom) { if (!sw->VegEstab.use) { printf("Establishment not used.\n"); } - _echo_inputs(&sw->Site, &sw->Model); - _echo_VegEstab(sw->Site.width, sw->VegEstab.parms, sw->VegEstab.count); - _echo_VegProd(sw->VegProd.veg, sw->VegProd.bare_cov); - _echo_outputs(OutDom); + echo_inputs(&sw->Site, &sw->Model); + echo_VegEstab(sw->Site.width, sw->VegEstab.parms, sw->VegEstab.count); + echo_VegProd(sw->VegProd.veg, sw->VegProd.bare_cov); + echo_outputs(OutDom); } #if defined(SWNETCDF) @@ -3581,11 +3815,12 @@ void SW_FILESTATUS_deepCopy( LOG_INFO *LogInfo ) { - IntUS key; + int key; OutPeriod pd; - int fileNum; - int numFiles = source_files->numOutFiles; - char **destFile = NULL, *srcFile = NULL; + unsigned int fileNum; + unsigned int numFiles = source_files->numOutFiles; + char **destFile = NULL; + char *srcFile = NULL; ForEachOutKey(key) { if (OutDom->nvar_OUT[key] > 0 && OutDom->use[key]) { @@ -3630,7 +3865,8 @@ void SW_OUTDOM_deepCopy( SW_OUT_DOM *source, SW_OUT_DOM *dest, LOG_INFO *LogInfo ) { - IntUS k, i; + int k; + int i; /* Copies output pointers as well */ memcpy(dest, source, sizeof(*dest)); @@ -3648,7 +3884,8 @@ void SW_OUTDOM_deepCopy( } #if defined(SWNETCDF) - int varNum, attNum; + int varNum; + int attNum; if (source->nvar_OUT[k] > 0 && source->use[k]) { @@ -3705,14 +3942,14 @@ void SW_OUTDOM_deepCopy( __In summary:__ The function SW_CTL_run_current_year() in file SW_Control.c calls: - - the function _end_day() in file SW_Control.c, for each day, which in turn - calls _collect_values() with (global) arguments `bFlush_output` = `FALSE` + - the function end_day() in file SW_Control.c, for each day, which in turn + calls collect_values() with (global) arguments `bFlush_output` = `FALSE` and `tOffset` = 1 - the function SW_OUT_flush(), after the last day of each year, which in - turn calls _collect_values() with (global) arguments + turn calls collect_values() with (global) arguments `bFlush_output` = TRUE and `tOffset` = 0 - The function _collect_values() + The function collect_values() -# calls SW_OUT_sum_today() for each of the \ref ObjType `otype` that produce output, i.e., `eSWC`, `eWTH`, `eVES`, and `eVPD`. SW_OUT_sum_today() loops over each \ref OutPeriod `pd` diff --git a/src/SW_Output_get_functions.c b/src/SW_Output_get_functions.c index d2e4d5f98..d7a4a7cc5 100644 --- a/src/SW_Output_get_functions.c +++ b/src/SW_Output_get_functions.c @@ -18,25 +18,30 @@ See the \ref out_algo "output algorithm documentation" for details. /* INCLUDES / DEFINES */ /* --------------------------------------------------- */ -#include "include/generic.h" // for RealD, IntU +#include "include/generic.h" // for IntU +#include "include/myMemory.h" // for sw_memccpy_custom #include "include/SW_datastructs.h" // for SW_RUN, SW_OUTTEXT -#include "include/SW_Defines.h" // for _OUTSEP, OUT_DIGITS, OUTSTRLEN +#include "include/SW_Defines.h" // for OUTSEP, OUT_DIGITS, OUTSTRLEN #include "include/SW_Output.h" // for get_aet_text, get_biomass_text #include "include/SW_SoilWater.h" // for SW_SWRC_SWCtoSWP #include "include/SW_VegProd.h" // for BIO_INDEX, WUE_INDEX -#include // for snprintf, NULL #if defined(SWNETCDF) #include // defines NC_FILL_DOUBLE #endif +#if defined(SWNETCDF) || defined(RSOILWAT) +#include // for NULL +#endif + // Array-based output declarations: #if defined(SW_OUTARRAY) #include "include/SW_Output_outarray.h" // for iOUT, ncol_TimeOUT, get_outv... #endif #if defined(SW_OUTTEXT) -#include // for strcat +#include // for snprintf, NULL +#include // for memccpy #endif @@ -46,46 +51,61 @@ See the \ref out_algo "output algorithm documentation" for details. #ifdef STEPWAT static void format_IterationSummary( - RealD *p, RealD *psd, OutPeriod pd, IntUS N, SW_RUN *sw, size_t nrow_OUT[] + double *p, + double *psd, + OutPeriod pd, + IntUS N, + SW_RUN *sw, + const size_t nrow_OUT[] ) { IntUS i; size_t n; - RealD sd; + double sd; char str[OUTSTRLEN]; + size_t writeSize = OUTSTRLEN; + char *writePtr = sw->OutRun.sw_outstr_agg; + char *resPtr = NULL; SW_OUT_RUN *OutRun = &sw->OutRun; for (i = 0; i < N; i++) { n = iOUT(i, OutRun->irow_OUT[pd], nrow_OUT[pd], ncol_TimeOUT[pd]); sd = final_running_sd(sw->Model.runModelIterations, psd[n]); - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, p[n], - _OUTSEP, + OUTSEP, OUT_DIGITS, sd ); - strcat(OutRun->sw_outstr_agg, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr_agg - 1); } } static void format_IterationSummary2( - RealD *p, - RealD *psd, + double *p, + double *psd, OutPeriod pd, IntUS N1, IntUS offset, SW_RUN *sw, - size_t nrow_OUT[] + const size_t nrow_OUT[] ) { - IntUS k, i; + int k; + LyrIndex i; size_t n; - RealD sd; + double sd; char str[OUTSTRLEN]; + size_t strLen = strlen(sw->OutRun.sw_outstr_agg); + size_t writeSize = OUTSTRLEN - strLen; + char *writePtr = sw->OutRun.sw_outstr_agg + strLen; + char *resPtr = NULL; SW_OUT_RUN *OutRun = &sw->OutRun; for (k = 0; k < N1; k++) { @@ -95,18 +115,20 @@ static void format_IterationSummary2( ); sd = final_running_sd(sw->Model.runModelIterations, psd[n]); - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, p[n], - _OUTSEP, + OUTSEP, OUT_DIGITS, sd ); - strcat(OutRun->sw_outstr_agg, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr_agg - 1); } } } @@ -174,30 +196,37 @@ void get_co2effects_text(OutPeriod pd, SW_RUN *sw) { char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; TimeInt simyear = sw->Model.simyear; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; (void) pd; // hack to silence "-Wunused-parameter" ForEachVegType(k) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, sw->VegProd.veg[k].co2_multipliers[BIO_INDEX][simyear] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } ForEachVegType(k) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, sw->VegProd.veg[k].co2_multipliers[WUE_INDEX][simyear] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -207,7 +236,7 @@ void get_co2effects_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { int k; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_CO2Effects][pd]; + double *p = OutRun->p_OUT[eSW_CO2Effects][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -267,8 +296,8 @@ void get_co2effects_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_CO2Effects][pd], - *psd = OutRun->p_OUTsd[eSW_CO2Effects][pd]; + double *p = OutRun->p_OUT[eSW_CO2Effects][pd]; + double *psd = OutRun->p_OUTsd[eSW_CO2Effects][pd]; ForEachVegType(k) { iOUTIndex = iOUT( @@ -313,67 +342,90 @@ void get_biomass_text(OutPeriod pd, SW_RUN *sw) { int k; SW_VEGPROD_OUTPUTS *vo = sw->VegProd.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; // fCover for NVEGTYPES plus bare-ground - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, sw->VegProd.bare_cov.fCover ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); + ForEachVegType(k) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, sw->VegProd.veg[k].cov.fCover ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } // biomass (g/m2 as component of total) for NVEGTYPES plus totals and litter - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->biomass_total); - strcat(OutRun->sw_outstr, str); + (void + ) snprintf(str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->biomass_total); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); + ForEachVegType(k) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->veg[k].biomass_inveg ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->litter_total); - strcat(OutRun->sw_outstr, str); + (void + ) snprintf(str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->litter_total); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); // biolive (g/m2 as component of total) for NVEGTYPES plus totals - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->biolive_total); - strcat(OutRun->sw_outstr, str); + (void + ) snprintf(str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->biolive_total); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); + ForEachVegType(k) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->veg[k].biolive_inveg ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } // leaf area index [m2/m2] - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->LAI); - strcat(OutRun->sw_outstr, str); + (void) snprintf(str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->LAI); + sw_memccpy(writePtr, str, '\0', writeSize); } #endif @@ -384,7 +436,7 @@ void get_biomass_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Biomass][pd]; + double *p = OutRun->p_OUT[eSW_Biomass][pd]; #if defined(RSOILWAT) int i; @@ -544,13 +596,14 @@ void get_biomass_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { #elif defined(STEPWAT) void get_biomass_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - int k, i; + int k; + int i; SW_VEGPROD_OUTPUTS *vo = sw->VegProd.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Biomass][pd], - *psd = OutRun->p_OUTsd[eSW_Biomass][pd]; + double *p = OutRun->p_OUT[eSW_Biomass][pd]; + double *psd = OutRun->p_OUTsd[eSW_Biomass][pd]; // fCover for NVEGTYPES plus bare-ground iOUTIndex = @@ -656,17 +709,22 @@ establish this year. This check is for OUTTEXT. void get_estab_text(OutPeriod pd, SW_RUN *sw) { IntU i; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; - i = (IntU) pd; // silence `-Wunused-parameter` + (void) pd; // silence `-Wunused-parameter` for (i = 0; i < sw->VegEstab.count; i++) { - snprintf( - str, OUTSTRLEN, "%c%d", _OUTSEP, sw->VegEstab.parms[i]->estab_doy + (void) snprintf( + str, OUTSTRLEN, "%c%d", OUTSEP, sw->VegEstab.parms[i]->estab_doy ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -692,7 +750,7 @@ void get_estab_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Estab][pd]; + double *p = OutRun->p_OUT[eSW_Estab][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -736,8 +794,8 @@ void get_estab_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Estab][pd], - *psd = OutRun->p_OUTsd[eSW_Estab][pd]; + double *p = OutRun->p_OUT[eSW_Estab][pd]; + double *psd = OutRun->p_OUTsd[eSW_Estab][pd]; for (i = 0; i < sw->VegEstab.count; i++) { iOUTIndex = iOUT( @@ -777,26 +835,26 @@ void get_temp_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f%c%.*f%c%.*f%c%.*f%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->temp_max, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->temp_min, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->temp_avg, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceMax, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceMin, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceAvg ); @@ -819,7 +877,7 @@ void get_temp_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Temp][pd]; + double *p = OutRun->p_OUT[eSW_Temp][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -915,8 +973,8 @@ void get_temp_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Temp][pd], - *psd = OutRun->p_OUTsd[eSW_Temp][pd]; + double *p = OutRun->p_OUT[eSW_Temp][pd]; + double *psd = OutRun->p_OUTsd[eSW_Temp][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -997,23 +1055,23 @@ void get_precip_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f%c%.*f%c%.*f%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->ppt, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->rain, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->snow, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->snowmelt, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->snowloss ); @@ -1037,7 +1095,7 @@ void get_precip_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Precip][pd]; + double *p = OutRun->p_OUT[eSW_Precip][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1122,8 +1180,8 @@ void get_precip_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Precip][pd], - *psd = OutRun->p_OUTsd[eSW_Precip][pd]; + double *p = OutRun->p_OUT[eSW_Precip][pd]; + double *psd = OutRun->p_OUTsd[eSW_Precip][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -1197,21 +1255,26 @@ void get_vwcBulk_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachSoilLayer(i, sw->Site.n_layers) { /* vwcBulk at this point is identical to swcBulk */ - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->vwcBulk[i] / sw->Site.width[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -1233,7 +1296,7 @@ void get_vwcBulk_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_VWCBulk][pd]; + double *p = OutRun->p_OUT[eSW_VWCBulk][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1289,8 +1352,8 @@ void get_vwcBulk_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_VWCBulk][pd], - *psd = OutRun->p_OUTsd[eSW_VWCBulk][pd]; + double *p = OutRun->p_OUT[eSW_VWCBulk][pd]; + double *psd = OutRun->p_OUTsd[eSW_VWCBulk][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { /* vwcBulk at this point is identical to swcBulk */ @@ -1330,9 +1393,12 @@ void get_vwcBulk_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { */ void get_vwcMatric_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; - RealD convert; + double convert; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; @@ -1342,15 +1408,17 @@ void get_vwcMatric_text(OutPeriod pd, SW_RUN *sw) { convert = 1. / (1. - sw->Site.fractionVolBulk_gravel[i]) / sw->Site.width[i]; - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->vwcMatric[i] * convert ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -1368,12 +1436,12 @@ void get_vwcMatric_text(OutPeriod pd, SW_RUN *sw) { */ void get_vwcMatric_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { LyrIndex i; - RealD convert; + double convert; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_VWCMatric][pd]; + double *p = OutRun->p_OUT[eSW_VWCMatric][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1427,13 +1495,13 @@ void get_vwcMatric_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { */ void get_vwcMatric_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { LyrIndex i; - RealD convert; + double convert; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_VWCMatric][pd], - *psd = OutRun->p_OUTsd[eSW_VWCMatric][pd]; + double *p = OutRun->p_OUT[eSW_VWCMatric][pd]; + double *psd = OutRun->p_OUTsd[eSW_VWCMatric][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { /* vwcMatric at this point is identical to swcBulk */ @@ -1476,21 +1544,26 @@ void get_swa_text(OutPeriod pd, SW_RUN *sw) { int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachVegType(k) { ForEachSoilLayer(i, sw->Site.n_layers) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->SWA_VegType[k][i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } } @@ -1514,7 +1587,7 @@ void get_swa_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWA][pd]; + double *p = OutRun->p_OUT[eSW_SWA][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1579,7 +1652,8 @@ void get_swa_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWA][pd], *psd = OutRun->p_OUTsd[eSW_SWA][pd]; + double *p = OutRun->p_OUT[eSW_SWA][pd]; + double *psd = OutRun->p_OUTsd[eSW_SWA][pd]; ForEachVegType(k) { ForEachSoilLayer(i, sw->Site.n_layers) { @@ -1618,13 +1692,20 @@ void get_swcBulk_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachSoilLayer(i, sw->Site.n_layers) { - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->swcBulk[i]); - strcat(OutRun->sw_outstr, str); + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->swcBulk[i] + ); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -1646,7 +1727,7 @@ void get_swcBulk_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWCBulk][pd]; + double *p = OutRun->p_OUT[eSW_SWCBulk][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1701,8 +1782,8 @@ void get_swcBulk_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWCBulk][pd], - *psd = OutRun->p_OUTsd[eSW_SWCBulk][pd]; + double *p = OutRun->p_OUT[eSW_SWCBulk][pd]; + double *psd = OutRun->p_OUTsd[eSW_SWCBulk][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { iOUTIndex = iOUT( @@ -1764,10 +1845,13 @@ converting the averged swc. This also avoids converting for each day. added information that do not change throughout simulation runs */ void get_swpMatric_text(OutPeriod pd, SW_RUN *sw) { - RealD val; + double val; LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; /* Local LOG_INFO only because `SW_SWRC_SWCtoSWP()` requires it */ LOG_INFO local_log; @@ -1781,8 +1865,10 @@ void get_swpMatric_text(OutPeriod pd, SW_RUN *sw) { val = SW_SWRC_SWCtoSWP(vo->swpMatric[i], &sw->Site, i, &local_log); - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, val); - strcat(OutRun->sw_outstr, str); + (void) snprintf(str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, val); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -1805,7 +1891,7 @@ void get_swpMatric_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWPMatric][pd]; + double *p = OutRun->p_OUT[eSW_SWPMatric][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1857,15 +1943,15 @@ void get_swpMatric_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { information that do not change throughout simulation runs */ void get_swpMatric_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - RealD val; + double val; LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; LOG_INFO local_log; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWPMatric][pd], - *psd = OutRun->p_OUTsd[eSW_SWPMatric][pd]; + double *p = OutRun->p_OUT[eSW_SWPMatric][pd]; + double *psd = OutRun->p_OUTsd[eSW_SWPMatric][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { /* swpMatric at this point is identical to swcBulk */ @@ -1903,13 +1989,20 @@ void get_swaBulk_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachSoilLayer(i, sw->Site.n_layers) { - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->swaBulk[i]); - strcat(OutRun->sw_outstr, str); + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->swaBulk[i] + ); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -1931,7 +2024,7 @@ void get_swaBulk_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWABulk][pd]; + double *p = OutRun->p_OUT[eSW_SWABulk][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -1986,8 +2079,8 @@ void get_swaBulk_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWABulk][pd], - *psd = OutRun->p_OUTsd[eSW_SWABulk][pd]; + double *p = OutRun->p_OUT[eSW_SWABulk][pd]; + double *psd = OutRun->p_OUTsd[eSW_SWABulk][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { iOUTIndex = iOUT( @@ -2019,9 +2112,12 @@ void get_swaBulk_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { */ void get_swaMatric_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; - RealD convert; + double convert; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; @@ -2030,15 +2126,17 @@ void get_swaMatric_text(OutPeriod pd, SW_RUN *sw) { /* swaMatric at this point is identical to swaBulk */ convert = 1. / (1. - sw->Site.fractionVolBulk_gravel[i]); - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->swaMatric[i] * convert ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -2056,12 +2154,12 @@ void get_swaMatric_text(OutPeriod pd, SW_RUN *sw) { */ void get_swaMatric_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { LyrIndex i; - RealD convert; + double convert; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWAMatric][pd]; + double *p = OutRun->p_OUT[eSW_SWAMatric][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -2114,13 +2212,13 @@ void get_swaMatric_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { */ void get_swaMatric_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { LyrIndex i; - RealD convert; + double convert; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SWAMatric][pd], - *psd = OutRun->p_OUTsd[eSW_SWAMatric][pd]; + double *p = OutRun->p_OUT[eSW_SWAMatric][pd]; + double *psd = OutRun->p_OUTsd[eSW_SWAMatric][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { /* swaMatric at this point is identical to swaBulk */ @@ -2161,11 +2259,11 @@ void get_surfaceWater_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceWater ); @@ -2188,7 +2286,7 @@ void get_surfaceWater_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SurfaceWater][pd]; + double *p = OutRun->p_OUT[eSW_SurfaceWater][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -2224,8 +2322,8 @@ void get_surfaceWater_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SurfaceWater][pd], - *psd = OutRun->p_OUTsd[eSW_SurfaceWater][pd]; + double *p = OutRun->p_OUT[eSW_SurfaceWater][pd]; + double *psd = OutRun->p_OUTsd[eSW_SurfaceWater][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -2255,27 +2353,27 @@ OUTTEXT. information that do not change throughout simulation runs */ void get_runoffrunon_text(OutPeriod pd, SW_RUN *sw) { - RealD net; + double net; SW_WEATHER_OUTPUTS *vo = sw->Weather.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; net = vo->surfaceRunoff + vo->snowRunoff - vo->surfaceRunon; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f%c%.*f%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, net, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceRunoff, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->snowRunoff, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceRunon ); @@ -2299,7 +2397,7 @@ void get_runoffrunon_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Runoff][pd]; + double *p = OutRun->p_OUT[eSW_Runoff][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -2368,13 +2466,13 @@ STEPWAT. information that do not change throughout simulation runs */ void get_runoffrunon_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - RealD net; + double net; SW_WEATHER_OUTPUTS *vo = sw->Weather.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Runoff][pd], - *psd = OutRun->p_OUTsd[eSW_Runoff][pd]; + double *p = OutRun->p_OUT[eSW_Runoff][pd]; + double *psd = OutRun->p_OUTsd[eSW_Runoff][pd]; net = vo->surfaceRunoff + vo->snowRunoff - vo->surfaceRunon; @@ -2416,29 +2514,37 @@ void get_runoffrunon_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { information that do not change throughout simulation runs */ void get_transp_text(OutPeriod pd, SW_RUN *sw) { - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; int k; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + char *writeStr = OutRun->sw_outstr; + char *resPtr = NULL; - char str[OUTSTRLEN]; + char str[OUTSTRLEN] = {'\0'}; OutRun->sw_outstr[0] = '\0'; /* total transpiration */ ForEachSoilLayer(i, n_layers) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->transp_total[i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->transp_total[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writeStr, str, '\0', writeSize); + writeSize -= (resPtr - OutRun->sw_outstr - 1); + writeStr = resPtr - 1; } /* transpiration for each vegetation type */ ForEachVegType(k) { ForEachSoilLayer(i, n_layers) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->transp[k][i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->transp[k][i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writeStr, str, '\0', writeSize); + writeSize -= (resPtr - OutRun->sw_outstr - 1); + writeStr = resPtr - 1; } } } @@ -2456,13 +2562,14 @@ void get_transp_text(OutPeriod pd, SW_RUN *sw) { information that do not change throughout simulation runs */ void get_transp_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Transp][pd]; + double *p = OutRun->p_OUT[eSW_Transp][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -2554,14 +2661,15 @@ void get_transp_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { information that do not change throughout simulation runs */ void get_transp_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Transp][pd], - *psd = OutRun->p_OUTsd[eSW_Transp][pd]; + double *p = OutRun->p_OUT[eSW_Transp][pd]; + double *psd = OutRun->p_OUTsd[eSW_Transp][pd]; /* total transpiration */ ForEachSoilLayer(i, n_layers) { @@ -2648,15 +2756,20 @@ void get_evapSoil_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachEvapLayer(i, sw->Site.n_evap_lyrs) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->evap_baresoil[i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->evap_baresoil[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -2678,7 +2791,7 @@ void get_evapSoil_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_EvapSoil][pd]; + double *p = OutRun->p_OUT[eSW_EvapSoil][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -2733,8 +2846,8 @@ void get_evapSoil_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_EvapSoil][pd], - *psd = OutRun->p_OUTsd[eSW_EvapSoil][pd]; + double *p = OutRun->p_OUT[eSW_EvapSoil][pd]; + double *psd = OutRun->p_OUTsd[eSW_EvapSoil][pd]; ForEachEvapLayer(i, sw->Site.n_evap_lyrs) { iOUTIndex = iOUT( @@ -2771,38 +2884,40 @@ void get_evapSurface_text(OutPeriod pd, SW_RUN *sw) { int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; - snprintf( - OutRun->sw_outstr, - sizeof OutRun->sw_outstr, - "%c%.*f", - _OUTSEP, - OUT_DIGITS, - vo->total_evap - ); + (void + ) snprintf(str, sizeof str, "%c%.*f", OUTSEP, OUT_DIGITS, vo->total_evap); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); ForEachVegType(k) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->evap_veg[k] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->evap_veg[k] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->litter_evap, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->surfaceWater_evap ); - strcat(OutRun->sw_outstr, str); + sw_memccpy(writePtr, str, '\0', writeSize); } #endif @@ -2823,7 +2938,7 @@ void get_evapSurface_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_EvapSurface][pd]; + double *p = OutRun->p_OUT[eSW_EvapSurface][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -2913,8 +3028,8 @@ void get_evapSurface_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_EvapSurface][pd], - *psd = OutRun->p_OUTsd[eSW_EvapSurface][pd]; + double *p = OutRun->p_OUT[eSW_EvapSurface][pd]; + double *psd = OutRun->p_OUTsd[eSW_EvapSurface][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -2968,26 +3083,31 @@ void get_interception_text(OutPeriod pd, SW_RUN *sw) { int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; - snprintf( - OutRun->sw_outstr, - sizeof OutRun->sw_outstr, - "%c%.*f", - _OUTSEP, - OUT_DIGITS, - vo->total_int - ); + (void + ) snprintf(str, sizeof str, "%c%.*f", OUTSEP, OUT_DIGITS, vo->total_int); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); ForEachVegType(k) { - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->int_veg[k]); - strcat(OutRun->sw_outstr, str); + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->int_veg[k] + ); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } - snprintf(str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->litter_int); - strcat(OutRun->sw_outstr, str); + (void + ) snprintf(str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->litter_int); + sw_memccpy(writePtr, str, '\0', writeSize); } #endif @@ -3008,7 +3128,7 @@ void get_interception_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Interception][pd]; + double *p = OutRun->p_OUT[eSW_Interception][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -3082,8 +3202,8 @@ void get_interception_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Interception][pd], - *psd = OutRun->p_OUTsd[eSW_Interception][pd]; + double *p = OutRun->p_OUT[eSW_Interception][pd]; + double *psd = OutRun->p_OUTsd[eSW_Interception][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -3134,11 +3254,11 @@ void get_soilinf_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->soil_inf ); @@ -3161,7 +3281,7 @@ void get_soilinf_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SoilInf][pd]; + double *p = OutRun->p_OUT[eSW_SoilInf][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -3197,8 +3317,8 @@ void get_soilinf_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SoilInf][pd], - *psd = OutRun->p_OUTsd[eSW_SoilInf][pd]; + double *p = OutRun->p_OUT[eSW_SoilInf][pd]; + double *psd = OutRun->p_OUTsd[eSW_SoilInf][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -3231,15 +3351,20 @@ void get_lyrdrain_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; for (i = 0; i < sw->Site.n_layers - 1; i++) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->lyrdrain[i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->lyrdrain[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -3261,7 +3386,7 @@ void get_lyrdrain_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_LyrDrain][pd]; + double *p = OutRun->p_OUT[eSW_LyrDrain][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -3316,8 +3441,8 @@ void get_lyrdrain_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_LyrDrain][pd], - *psd = OutRun->p_OUTsd[eSW_LyrDrain][pd]; + double *p = OutRun->p_OUT[eSW_LyrDrain][pd]; + double *psd = OutRun->p_OUTsd[eSW_LyrDrain][pd]; for (i = 0; i < sw->Site.n_layers - 1; i++) { iOUTIndex = iOUT( @@ -3350,29 +3475,37 @@ void get_lyrdrain_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { */ void get_hydred_text(OutPeriod pd, SW_RUN *sw) { /* 20101020 (drs) added */ - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; /* total hydraulic redistribution */ ForEachSoilLayer(i, n_layers) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->hydred_total[i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->hydred_total[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } /* hydraulic redistribution for each vegetation type */ ForEachVegType(k) { ForEachSoilLayer(i, n_layers) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->hydred[k][i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->hydred[k][i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } } @@ -3390,13 +3523,14 @@ void get_hydred_text(OutPeriod pd, SW_RUN *sw) { information that do not change throughout simulation runs */ void get_hydred_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_HydRed][pd]; + double *p = OutRun->p_OUT[eSW_HydRed][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -3493,14 +3627,15 @@ void get_hydred_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { information that do not change throughout simulation runs */ void get_hydred_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; int k; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_HydRed][pd], - *psd = OutRun->p_OUTsd[eSW_HydRed][pd]; + double *p = OutRun->p_OUT[eSW_HydRed][pd]; + double *psd = OutRun->p_OUTsd[eSW_HydRed][pd]; /* total hydraulic redistribution */ ForEachSoilLayer(i, n_layers) { @@ -3557,26 +3692,26 @@ void get_aet_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f%c%.*f%c%.*f%c%.*f%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->aet, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->tran, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->esoil, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->ecnw, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->esurf, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo2->snowloss // should be `vo->esnow` ); @@ -3600,7 +3735,7 @@ void get_aet_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_AET][pd]; + double *p = OutRun->p_OUT[eSW_AET][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -3697,7 +3832,8 @@ void get_aet_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_AET][pd], *psd = OutRun->p_OUTsd[eSW_AET][pd]; + double *p = OutRun->p_OUT[eSW_AET][pd]; + double *psd = OutRun->p_OUTsd[eSW_AET][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -3771,23 +3907,23 @@ void get_pet_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f%c%.*f%c%.*f%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->pet, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->H_oh, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->H_ot, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->H_gh, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->H_gt ); @@ -3810,7 +3946,7 @@ void get_pet_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_PET][pd]; + double *p = OutRun->p_OUT[eSW_PET][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -3888,7 +4024,8 @@ void get_pet_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_PET][pd], *psd = OutRun->p_OUTsd[eSW_PET][pd]; + double *p = OutRun->p_OUT[eSW_PET][pd]; + double *psd = OutRun->p_OUTsd[eSW_PET][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -3933,26 +4070,35 @@ void get_pet_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { information that do not change throughout simulation runs */ void get_wetdays_text(OutPeriod pd, SW_RUN *sw) { - LyrIndex i, n_layers = sw->Site.n_layers; + LyrIndex i; + LyrIndex n_layers = sw->Site.n_layers; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; if (pd == eSW_Day) { ForEachSoilLayer(i, n_layers) { - snprintf( - str, OUTSTRLEN, "%c%i", _OUTSEP, (sw->SoilWat.is_wet[i]) ? 1 : 0 + (void) snprintf( + str, OUTSTRLEN, "%c%i", OUTSEP, (sw->SoilWat.is_wet[i]) ? 1 : 0 ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } else { SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; ForEachSoilLayer(i, n_layers) { - snprintf(str, OUTSTRLEN, "%c%i", _OUTSEP, (int) vo->wetdays[i]); - strcat(OutRun->sw_outstr, str); + (void + ) snprintf(str, OUTSTRLEN, "%c%i", OUTSEP, (int) vo->wetdays[i]); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } } @@ -3974,7 +4120,7 @@ void get_wetdays_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_WetDays][pd]; + double *p = OutRun->p_OUT[eSW_WetDays][pd]; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; #if defined(RSOILWAT) @@ -4033,8 +4179,8 @@ void get_wetdays_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_WetDays][pd], - *psd = OutRun->p_OUTsd[eSW_WetDays][pd]; + double *p = OutRun->p_OUT[eSW_WetDays][pd]; + double *psd = OutRun->p_OUTsd[eSW_WetDays][pd]; if (pd == eSW_Day) { ForEachSoilLayer(i, sw->Site.n_layers) { @@ -4088,14 +4234,14 @@ void get_snowpack_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->snowpack, - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->snowdepth ); @@ -4118,7 +4264,7 @@ void get_snowpack_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SnowPack][pd]; + double *p = OutRun->p_OUT[eSW_SnowPack][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -4166,8 +4312,8 @@ void get_snowpack_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SnowPack][pd], - *psd = OutRun->p_OUTsd[eSW_SnowPack][pd]; + double *p = OutRun->p_OUT[eSW_SnowPack][pd]; + double *psd = OutRun->p_OUTsd[eSW_SnowPack][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -4204,11 +4350,11 @@ void get_deepswc_text(OutPeriod pd, SW_RUN *sw) { SW_OUT_RUN *OutRun = &sw->OutRun; OutRun->sw_outstr[0] = '\0'; - snprintf( + (void) snprintf( OutRun->sw_outstr, sizeof OutRun->sw_outstr, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->deep ); @@ -4231,7 +4377,7 @@ void get_deepswc_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_DeepSWC][pd]; + double *p = OutRun->p_OUT[eSW_DeepSWC][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -4267,8 +4413,8 @@ void get_deepswc_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_DeepSWC][pd], - *psd = OutRun->p_OUTsd[eSW_DeepSWC][pd]; + double *p = OutRun->p_OUT[eSW_DeepSWC][pd]; + double *psd = OutRun->p_OUTsd[eSW_DeepSWC][pd]; iOUTIndex = iOUT(0, OutRun->irow_OUT[pd], OutDom->nrow_OUT[pd], ncol_TimeOUT[pd]); @@ -4300,35 +4446,44 @@ void get_soiltemp_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachSoilLayer(i, sw->Site.n_layers) { - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->maxLyrTemperature[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); - snprintf( + (void) snprintf( str, OUTSTRLEN, "%c%.*f", - _OUTSEP, + OUTSEP, OUT_DIGITS, vo->minLyrTemperature[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->avgLyrTemp[i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->avgLyrTemp[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -4350,7 +4505,7 @@ void get_soiltemp_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SoilTemp][pd]; + double *p = OutRun->p_OUT[eSW_SoilTemp][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -4460,8 +4615,8 @@ void get_soiltemp_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_SoilTemp][pd], - *psd = OutRun->p_OUTsd[eSW_SoilTemp][pd]; + double *p = OutRun->p_OUT[eSW_SoilTemp][pd]; + double *psd = OutRun->p_OUTsd[eSW_SoilTemp][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { iOUTIndex = iOUT( @@ -4519,15 +4674,20 @@ void get_frozen_text(OutPeriod pd, SW_RUN *sw) { LyrIndex i; SW_SOILWAT_OUTPUTS *vo = sw->SoilWat.p_oagg[pd]; SW_OUT_RUN *OutRun = &sw->OutRun; + size_t writeSize = (size_t) (MAX_LAYERS * OUTSTRLEN); + char *writePtr = OutRun->sw_outstr; + char *resPtr = NULL; char str[OUTSTRLEN]; OutRun->sw_outstr[0] = '\0'; ForEachSoilLayer(i, sw->Site.n_layers) { - snprintf( - str, OUTSTRLEN, "%c%.*f", _OUTSEP, OUT_DIGITS, vo->lyrFrozen[i] + (void) snprintf( + str, OUTSTRLEN, "%c%.*f", OUTSEP, OUT_DIGITS, vo->lyrFrozen[i] ); - strcat(OutRun->sw_outstr, str); + resPtr = (char *) sw_memccpy(writePtr, str, '\0', writeSize); + writePtr = resPtr - 1; + writeSize -= (resPtr - OutRun->sw_outstr - 1); } } #endif @@ -4549,7 +4709,7 @@ void get_frozen_mem(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Frozen][pd]; + double *p = OutRun->p_OUT[eSW_Frozen][pd]; #if defined(RSOILWAT) get_outvalleader( @@ -4604,8 +4764,8 @@ void get_frozen_agg(OutPeriod pd, SW_RUN *sw, SW_OUT_DOM *OutDom) { size_t iOUTIndex = 0; SW_OUT_RUN *OutRun = &sw->OutRun; - RealD *p = OutRun->p_OUT[eSW_Frozen][pd], - *psd = OutRun->p_OUTsd[eSW_Frozen][pd]; + double *p = OutRun->p_OUT[eSW_Frozen][pd]; + double *psd = OutRun->p_OUTsd[eSW_Frozen][pd]; ForEachSoilLayer(i, sw->Site.n_layers) { iOUTIndex = iOUT( diff --git a/src/SW_Output_outarray.c b/src/SW_Output_outarray.c index 99569f8f9..9765886a2 100644 --- a/src/SW_Output_outarray.c +++ b/src/SW_Output_outarray.c @@ -18,7 +18,7 @@ See the \ref out_algo "output algorithm documentation" for details. /* --------------------------------------------------- */ #include "include/SW_Output_outarray.h" // for SW_OUT_calc_iOUToffset, SW_O... -#include "include/generic.h" // for IntUS, IntU, Bool, RealD +#include "include/generic.h" // for IntUS, IntU, Bool #include "include/SW_datastructs.h" // for LOG_INFO, SW_MODEL #include "include/SW_Defines.h" // for eSW_Day, SW_OUTNMAXVARS, SW_... #include "include/SW_Output.h" // for ForEachOutKey @@ -70,16 +70,17 @@ const IntUS ncol_TimeOUT[SW_OUTNPERIODS] = {2, 2, 2, 1}; @param[out] nrow_OUT Number of output rows for each output period */ void SW_OUT_set_nrow( - SW_MODEL *SW_Model, Bool use_OutPeriod[], size_t nrow_OUT[] + SW_MODEL *SW_Model, const Bool use_OutPeriod[], size_t nrow_OUT[] ) { - TimeInt i; - size_t n_yrs; - IntU startyear, endyear; #ifdef SWDEBUG int debug = 0; #endif - startyear = SW_Model->startyr; + TimeInt i; + size_t n_yrs; + IntU startyear = SW_Model->startyr; + IntU endyear; + #ifdef STEPWAT n_yrs = SW_Model->runModelYears; @@ -134,7 +135,8 @@ void SW_OUT_set_nrow( information that may change throughout simulation runs */ void SW_OUT_deconstruct_outarray(SW_OUT_RUN *OutRun) { - IntUS i, k; + int i; + int k; ForEachOutKey(k) { for (i = 0; i < SW_OUTNPERIODS; i++) { @@ -175,10 +177,10 @@ void SW_OUT_deconstruct_outarray(SW_OUT_RUN *OutRun) { void get_outvalleader( SW_MODEL *SW_Model, OutPeriod pd, - size_t irow_OUT[], - size_t nrow_OUT[], + const size_t irow_OUT[], + const size_t nrow_OUT[], TimeInt tOffset, - RealD *p + double *p ) { p[irow_OUT[pd] + nrow_OUT[pd] * 0] = SW_Model->simyear; @@ -199,6 +201,7 @@ void get_outvalleader( break; case eSW_Year: + default: break; } } @@ -217,8 +220,8 @@ void get_outvalleader( @param[in] x The new value to add to the running mean and running standard deviation */ -void do_running_agg(RealD *p, RealD *psd, size_t k, IntU n, RealD x) { - RealD prev_val = p[k]; +void do_running_agg(double *p, double *psd, size_t k, IntU n, double x) { + double prev_val = p[k]; p[k] = get_running_mean(n, prev_val, x); psd[k] = @@ -244,8 +247,10 @@ Note: Compare with function `setGlobalrSOILWAT2_OutputVariables` in void SW_OUT_construct_outarray( SW_OUT_DOM *OutDom, SW_OUT_RUN *OutRun, LOG_INFO *LogInfo ) { - IntUS i, k; - size_t size, s = sizeof(RealD); + int i; + int k; + size_t size; + size_t s = sizeof(double); OutPeriod timeStepOutPeriod; ForEachOutKey(k) { @@ -258,7 +263,7 @@ void SW_OUT_construct_outarray( size = OutDom->nrow_OUT[timeStepOutPeriod] * (OutDom->ncol_OUT[k] + ncol_TimeOUT[timeStepOutPeriod]); - OutRun->p_OUT[k][timeStepOutPeriod] = (RealD *) Mem_Calloc( + OutRun->p_OUT[k][timeStepOutPeriod] = (double *) Mem_Calloc( size, s, "SW_OUT_construct_outarray()", LogInfo ); if (LogInfo->stopRun) { @@ -267,7 +272,7 @@ void SW_OUT_construct_outarray( #endif #if defined(STEPWAT) - OutRun->p_OUTsd[k][timeStepOutPeriod] = (RealD *) Mem_Calloc( + OutRun->p_OUTsd[k][timeStepOutPeriod] = (double *) Mem_Calloc( size, s, "SW_OUT_construct_outarray()", LogInfo ); if (LogInfo->stopRun) { @@ -301,14 +306,20 @@ void SW_OUT_construct_outarray( p_OUT (array of size SW_OUTNKEYS by SW_OUTNPERIODS by SW_OUTNMAXVARS). */ void SW_OUT_calc_iOUToffset( - size_t nrow_OUT[], - IntUS nvar_OUT[], + const size_t nrow_OUT[], + const IntUS nvar_OUT[], IntUS nsl_OUT[][SW_OUTNMAXVARS], IntUS npft_OUT[][SW_OUTNMAXVARS], size_t iOUToffset[][SW_OUTNPERIODS][SW_OUTNMAXVARS] ) { - int key, ivar, iprev, pd; - size_t tmp, tmp_nsl, tmp_npft, tmp_header; + int key; + int ivar; + int iprev; + int pd; + size_t tmp; + size_t tmp_nsl; + size_t tmp_npft; + size_t tmp_header; ForEachOutPeriod(pd) { tmp_header = nrow_OUT[pd] * ncol_TimeOUT[pd]; diff --git a/src/SW_Output_outtext.c b/src/SW_Output_outtext.c index 559e2ae3d..a65aa343b 100644 --- a/src/SW_Output_outtext.c +++ b/src/SW_Output_outtext.c @@ -23,11 +23,11 @@ See the \ref out_algo "output algorithm documentation" for details. #include "include/generic.h" // for Bool, swFALSE, SOILWAT, IntUS #include "include/myMemory.h" // for Mem_Malloc #include "include/SW_datastructs.h" // for LOG_INFO -#include "include/SW_Defines.h" // for _OUTSEP, OutPeriod, ForEachOu... +#include "include/SW_Defines.h" // for OUTSEP, OutPeriod, ForEachOu... #include "include/SW_Output.h" // for pd2longstr, ForEachOutKey #include // for snprintf, fflush, fprintf #include // for free -#include // for strcat, strcpy +#include // for memccpy #if (defined(SOILWAT) && !defined(SWNETCDF)) || defined(STEPWAT) #include "include/SW_Files.h" // for eOutputDaily, eOutputDaily_soil @@ -56,7 +56,7 @@ Active if @ref SW_OUT_DOM.print_IterationSummary is TRUE /* Local Function Definitions */ /* --------------------------------------------------- */ -static void _create_csv_headers( +static void create_csv_headers( SW_OUT_DOM *OutDom, OutPeriod pd, char *str_reg, @@ -71,29 +71,40 @@ static void _create_csv_headers( LogError( LogInfo, LOGERROR, - "'_create_csv_headers': value TRUE for " + "'create_csv_headers': value TRUE for " "argument 'does_agg' is not implemented for SOILWAT2-standalone." ); return; // Exit function prematurely due to error } #endif - unsigned int i, k; + unsigned int i; + unsigned int k; + int resSNP; char key[50]; Bool isTrue = swFALSE; - size_t size_help = n_layers * OUTSTRLEN; - char *str_help1, *str_help2; + size_t size_help = (size_t) (n_layers) *OUTSTRLEN; + char *str_help1; + char *str_help2; + + size_t writeSizeHelp = size_help; + size_t writeSizeReg = (size_t) (2 * OUTSTRLEN); + size_t writeSizeSoil = (size_t) (n_layers) *OUTSTRLEN; + char *writePtrHelp = NULL; + char *resPtr = NULL; + char *writePtrSoil = NULL; + char *writePtrReg = NULL; str_help1 = (char *) Mem_Malloc( - sizeof(char) * size_help, "_create_csv_headers()", LogInfo + sizeof(char) * size_help, "create_csv_headers()", LogInfo ); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } str_help2 = (char *) Mem_Malloc( - sizeof(char) * size_help, "_create_csv_headers()", LogInfo + sizeof(char) * size_help, "create_csv_headers()", LogInfo ); if (LogInfo->stopRun) { free(str_help1); @@ -104,7 +115,12 @@ static void _create_csv_headers( str_reg[0] = (char) '\0'; str_soil[0] = (char) '\0'; + writePtrReg = str_reg; + writePtrSoil = str_soil; + ForEachOutKey(k) { + writePtrHelp = str_help2; + isTrue = (Bool) (OutDom->use[k] && has_OutPeriod_inUse( pd, (OutKey) k, @@ -112,44 +128,62 @@ static void _create_csv_headers( OutDom->timeSteps )); if (isTrue) { - strcpy(key, key2str[k]); + (void) sw_memccpy(key, (char *) key2str[k], '\0', sizeof key); str_help2[0] = '\0'; for (i = 0; i < OutDom->ncol_OUT[k]; i++) { if (does_agg) { - snprintf( + resSNP = snprintf( str_help1, size_help, "%c%s_%s_Mean%c%s_%s_SD", - _OUTSEP, + OUTSEP, key, OutDom->colnames_OUT[k][i], - _OUTSEP, + OUTSEP, key, OutDom->colnames_OUT[k][i] ); } else { - snprintf( + resSNP = snprintf( str_help1, size_help, "%c%s_%s", - _OUTSEP, + OUTSEP, key, OutDom->colnames_OUT[k][i] ); } - strcat(str_help2, str_help1); + if (resSNP < 0 || (unsigned) resSNP >= size_help) { + LogError(LogInfo, LOGERROR, "csv-header is too long."); + goto freeMem; // Exit function prematurely due to error + } + + resPtr = (char *) sw_memccpy( + writePtrHelp, str_help1, '\0', writeSizeHelp + ); + writePtrHelp = resPtr - 1; + writeSizeHelp -= (resPtr - writePtrHelp - 1); } if (OutDom->has_sl[k]) { - strcat((char *) str_soil, str_help2); + resPtr = (char *) sw_memccpy( + writePtrSoil, str_help2, '\0', writeSizeSoil + ); + writeSizeSoil -= (resPtr - str_soil - 1); + writePtrSoil = resPtr - 1; } else { - strcat((char *) str_reg, str_help2); + resPtr = (char *) sw_memccpy( + writePtrReg, str_help2, '\0', writeSizeReg + ); + writeSizeReg -= (resPtr - str_reg - 1); + writePtrReg = resPtr - 1; } } } +freeMem: free(str_help1); free(str_help2); } @@ -167,7 +201,7 @@ static void _create_csv_headers( @param[out] LogInfo Holds information on warnings and errors */ /***********************************************************/ -static void _create_csv_files( +static void create_csv_files( SW_FILE_STATUS *SW_FileStatus, OutPeriod pd, char *InFiles[], @@ -200,25 +234,28 @@ static void _create_csv_files( static void get_outstrheader(OutPeriod pd, char *str, size_t sizeof_str) { switch (pd) { case eSW_Day: - snprintf( - str, sizeof_str, "%s%c%s", "Year", _OUTSEP, pd2longstr[eSW_Day] + (void) snprintf( + str, sizeof_str, "%s%c%s", "Year", OUTSEP, pd2longstr[eSW_Day] ); break; case eSW_Week: - snprintf( - str, sizeof_str, "%s%c%s", "Year", _OUTSEP, pd2longstr[eSW_Week] + (void) snprintf( + str, sizeof_str, "%s%c%s", "Year", OUTSEP, pd2longstr[eSW_Week] ); break; case eSW_Month: - snprintf( - str, sizeof_str, "%s%c%s", "Year", _OUTSEP, pd2longstr[eSW_Month] + (void) snprintf( + str, sizeof_str, "%s%c%s", "Year", OUTSEP, pd2longstr[eSW_Month] ); break; case eSW_Year: - snprintf(str, sizeof_str, "%s", "Year"); + (void) sw_memccpy(str, "Year", '\0', sizeof_str); + break; + + default: break; } } @@ -231,7 +268,7 @@ static void get_outstrheader(OutPeriod pd, char *str, size_t sizeof_str) { \return `name_flagiteration.ext` */ -static void _create_filename_ST( +static void create_filename_ST( char *str, char *flag, int iteration, @@ -239,7 +276,9 @@ static void _create_filename_ST( size_t sizeof_filename, LOG_INFO *LogInfo ) { - int startIndex = 0, strLen = 0; // For `sw_strtok()` + size_t startIndex = 0; + size_t strLen = 0; // For `sw_strtok()` + int resSNP; char *basename; char *ext; @@ -254,7 +293,7 @@ static void _create_filename_ST( // Put new file together if (iteration > 0) { - snprintf( + resSNP = snprintf( filename, sizeof_filename, "%s_%s%d.%s", @@ -264,10 +303,18 @@ static void _create_filename_ST( ext ); } else { - snprintf(filename, sizeof_filename, "%s_%s.%s", basename, flag, ext); + resSNP = snprintf( + filename, sizeof_filename, "%s_%s.%s", basename, flag, ext + ); } free(fileDup); + + if (resSNP < 0 || (unsigned) resSNP >= sizeof_filename) { + LogError( + LogInfo, LOGERROR, "csv file name is too long: '%s'", filename + ); + } } /** @@ -287,7 +334,7 @@ name if -i flag used in STEPWAT2. Set to a negative value otherwise. @param LogInfo Holds information on warnings and errors */ /***********************************************************/ -static void _create_csv_file_ST( +static void create_csv_file_ST( int iteration, OutPeriod pd, char *InFiles[], @@ -303,7 +350,7 @@ static void _create_csv_file_ST( // assumes a specific order of `SW_FileIndex` --> fix and create // something that allows subsetting such as `eOutputFile[pd]` or // append time period to a basename, etc. - _create_filename_ST( + create_filename_ST( InFiles[eOutputDaily + pd], "agg", 0, @@ -322,7 +369,7 @@ static void _create_csv_file_ST( } if (FileStatus->make_soil[pd]) { - _create_filename_ST( + create_filename_ST( InFiles[eOutputDaily_soil + pd], "agg", 0, @@ -353,7 +400,7 @@ static void _create_csv_file_ST( } if (FileStatus->make_regular[pd]) { - _create_filename_ST( + create_filename_ST( InFiles[eOutputDaily + pd], "rep", iteration, @@ -372,7 +419,7 @@ static void _create_csv_file_ST( } if (FileStatus->make_soil[pd]) { - _create_filename_ST( + create_filename_ST( InFiles[eOutputDaily_soil + pd], "rep", iteration, @@ -421,7 +468,7 @@ void SW_OUT_create_textfiles( ForEachOutPeriod(pd) { if (OutDom->use_OutPeriod[pd]) { - _create_csv_files(SW_FileStatus, pd, InFiles, LogInfo); + create_csv_files(SW_FileStatus, pd, InFiles, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -458,7 +505,7 @@ void SW_OUT_create_summary_files( ForEachOutPeriod(p) { if (OutDom->use_OutPeriod[p]) { - _create_csv_file_ST(-1, p, InFiles, SW_FileStatus, LogInfo); + create_csv_file_ST(-1, p, InFiles, SW_FileStatus, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -494,7 +541,7 @@ void SW_OUT_create_iteration_files( ForEachOutPeriod(p) { if (OutDom->use_OutPeriod[p]) { - _create_csv_file_ST(iteration, p, InFiles, SW_FileStatus, LogInfo); + create_csv_file_ST(iteration, p, InFiles, SW_FileStatus, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -541,35 +588,38 @@ void get_outstrleader( ) { switch (pd) { case eSW_Day: - snprintf( - str, sizeof_str, "%d%c%d", SW_Model->simyear, _OUTSEP, SW_Model->doy + (void) snprintf( + str, sizeof_str, "%d%c%d", SW_Model->simyear, OUTSEP, SW_Model->doy ); break; case eSW_Week: - snprintf( + (void) snprintf( str, sizeof_str, "%d%c%d", SW_Model->simyear, - _OUTSEP, + OUTSEP, (SW_Model->week + 1) - tOffset ); break; case eSW_Month: - snprintf( + (void) snprintf( str, sizeof_str, "%d%c%d", SW_Model->simyear, - _OUTSEP, + OUTSEP, (SW_Model->month + 1) - tOffset ); break; case eSW_Year: - snprintf(str, sizeof_str, "%d", SW_Model->simyear); + (void) snprintf(str, sizeof_str, "%d", SW_Model->simyear); + break; + + default: break; } } @@ -582,7 +632,7 @@ goes through all values and if the value is defined to be used it creates the header in the output file. @note The functions SW_OUT_set_ncol() and SW_OUT_set_colnames() must -be called before _create_csv_headers(); otherwise, `ncol_OUT` and +be called before create_csv_headers(); otherwise, `ncol_OUT` and `colnames_OUT` are not set. @param OutDom Struct of type SW_OUT_DOM that holds output @@ -605,8 +655,8 @@ void write_headers_to_csv( FILE *fp_reg, FILE *fp_soil, Bool does_agg, - Bool make_regular[], - Bool make_soil[], + const Bool make_regular[], + const Bool make_soil[], LyrIndex n_layers, LOG_INFO *LogInfo ) { @@ -617,8 +667,9 @@ void write_headers_to_csv( header_reg[2 * OUTSTRLEN]; // 26500 characters required for 25 soil layers and does_agg = TRUE - size_t size_hs = n_layers * OUTSTRLEN; + size_t size_hs = (size_t) (n_layers) *OUTSTRLEN; char *header_soil; + int fprintRes = 0; header_soil = (char *) Mem_Malloc( sizeof(char) * size_hs, "write_headers_to_csv()", LogInfo @@ -630,7 +681,7 @@ void write_headers_to_csv( // Acquire headers get_outstrheader(pd, str_time, sizeof str_time); - _create_csv_headers( + create_csv_headers( OutDom, pd, header_reg, header_soil, does_agg, n_layers, LogInfo ); if (LogInfo->stopRun) { @@ -640,13 +691,43 @@ void write_headers_to_csv( // Write headers to files if (make_regular[pd]) { - fprintf(fp_reg, "%s%s\n", str_time, header_reg); - fflush(fp_reg); + fprintRes = fprintf(fp_reg, "%s%s\n", str_time, header_reg); + + if (fprintRes < 0) { + LogError( + LogInfo, + LOGERROR, + "Could not write headers to \"regular\" CSVs." + ); + return; /* Exit prematurely due to error */ + } + + if (fflush(fp_reg) == EOF) { + LogError( + LogInfo, + LOGERROR, + "Could note write headers to \"regular\" CSVs." + ); + return; /* Exit prematurely due to error */ + } } if (make_soil[pd]) { - fprintf(fp_soil, "%s%s\n", str_time, header_soil); - fflush(fp_soil); + fprintRes = fprintf(fp_soil, "%s%s\n", str_time, header_soil); + + if (fprintRes < 0) { + LogError( + LogInfo, LOGERROR, "Could not write headers to \"soil\" CSVs." + ); + return; /* Exit prematurely due to error */ + } + + if (fflush(fp_soil) == EOF) { + LogError( + LogInfo, LOGERROR, "Could note flush headers to \"soil\" CSVs." + ); + return; /* Exit prematurely due to error */ + } } free(header_soil); @@ -655,11 +736,12 @@ void write_headers_to_csv( void find_TXToutputSoilReg_inUse( Bool make_soil[], Bool make_regular[], - Bool has_sl[], + const Bool has_sl[], OutPeriod timeSteps[][SW_OUTNPERIODS], IntUS used_OUTNPERIODS ) { - IntUS i, k; + int i; + int k; ForEachOutPeriod(i) { make_soil[i] = swFALSE; @@ -694,7 +776,9 @@ void SW_OUT_close_textfiles( SW_FILE_STATUS *SW_FileStatus, SW_OUT_DOM *OutDom, LOG_INFO *LogInfo ) { - Bool close_regular = swFALSE, close_layers = swFALSE, close_aggs = swFALSE; + Bool close_regular = swFALSE; + Bool close_layers = swFALSE; + Bool close_aggs = swFALSE; OutPeriod p; diff --git a/src/SW_Site.c b/src/SW_Site.c index 4db5f06fa..ba8a92aec 100644 --- a/src/SW_Site.c +++ b/src/SW_Site.c @@ -16,17 +16,17 @@ siteparam.in 10/19/2010 (drs) added HydraulicRedistribution flag, and maxCondroot, - swp50, and shapeCond parameters to SW_SIT_read() and _echo_inputs() + swp50, and shapeCond parameters to SW_SIT_read() and echo_inputs() 07/20/2011 (drs) updated _read_layers() to read impermeability values from each soil layer from soils.in file added calculation for saturated swc in - water_eqn() updated _echo_inputs() to print impermeability and saturated swc + water_eqn() updated echo_inputs() to print impermeability and saturated swc values 09/08/2011 (drs) moved all hydraulic redistribution parameters to SW_VegProd.h struct VegType - 09/15/2011 (drs) deleted albedo from SW_SIT_read() and _echo_inputs(): + 09/15/2011 (drs) deleted albedo from SW_SIT_read() and echo_inputs(): moved it to SW_VegProd.h to make input vegetation type dependent 02/03/2012 (drs) if input of SWCmin < 0 then estimate SWCmin with @@ -37,24 +37,24 @@ 02/04/2012 (drs) added calculation of swc at SWPcrit for each vegetation type and layer to function 'init_site_info()' added vwc/swc at SWPcrit to - '_echo_inputs()' + 'echo_inputs()' 05/24/2012 (DLM) edited SW_SIT_read(void) function to be able to read in Soil Temperature constants from siteparam.in file - 05/24/2012 (DLM) edited _echo_inputs(void) function to echo the Soil + 05/24/2012 (DLM) edited echo_inputs(void) function to echo the Soil Temperature constants to the logfile 05/25/2012 (DLM) edited _read_layers( void) function to read in the initial soil temperature for each layer - 05/25/2012 (DLM) edited _echo_inputs( void) function to echo the read in soil + 05/25/2012 (DLM) edited echo_inputs( void) function to echo the read in soil temperatures for each layer - 05/30/2012 (DLM) edited _read_layers & _echo_inputs functions to read in/echo + 05/30/2012 (DLM) edited _read_layers & echo_inputs functions to read in/echo the deltaX parameter - 05/31/2012 (DLM) edited _read_layers & _echo_inputs functions to read in/echo + 05/31/2012 (DLM) edited _read_layers & echo_inputs functions to read in/echo stMaxDepth & use_soil_temp variables 05/31/2012 (DLM) edited init_site_info(void) to check if stMaxDepth & stDeltaX @@ -63,13 +63,13 @@ 11/06/2012 (clk) In SW_SIT_read(void), added lines to read in aspect and slope from siteparam.in - 11/06/2012 (clk) In _echo_inputs(void), added lines to echo aspect and + 11/06/2012 (clk) In echo_inputs(void), added lines to echo aspect and slope to logfile 11/30/2012 (clk) In SW_SIT_read(void), added lines to read in percentRunoff from siteparam.in - 11/30/2012 (clk) In _echo_inputs(void), added lines to echo percentRunoff + 11/30/2012 (clk) In echo_inputs(void), added lines to echo percentRunoff to logfile 04/16/2013 (clk) changed the water_eqn to use the fraction of gravel @@ -118,11 +118,11 @@ #include "include/SW_Main_lib.h" // for sw_init_logs #include "include/SW_SoilWater.h" // for SW_SWRC_SWCtoSWP, SW_SWRC_SWPtoSWC #include "include/SW_VegProd.h" // for key2veg, get_critical_rank, sum_... +#include // for UINT_MAX #include // for fmod #include // for printf, sscanf, FILE, NULL, stdout -#include // for atof, atoi, free -#include // for strcpy, memset - +#include // for free, strod, strtol +#include // for memset /* =================================================== */ /* Global Variables */ @@ -135,7 +135,9 @@ - Order must exactly match "indices of `swrc2str`" - See details in section \ref swrc_ptf */ -char const *swrc2str[N_SWRCs] = {"Campbell1974", "vanGenuchten1980", "FXW"}; +const char *const swrc2str[N_SWRCs] = { + "Campbell1974", "vanGenuchten1980", "FXW" +}; /** Character representation of implemented Pedotransfer Functions (PTF) @@ -145,7 +147,7 @@ char const *swrc2str[N_SWRCs] = {"Campbell1974", "vanGenuchten1980", "FXW"}; - See details in section \ref swrc_ptf - `rSOILWAT2` may implemented additional PTFs */ -char const *ptf2str[N_PTFs] = {"Cosby1984AndOthers", "Cosby1984"}; +const char *const ptf2str[N_PTFs] = {"Cosby1984AndOthers", "Cosby1984"}; /* =================================================== */ /* Local Function Definitions */ @@ -164,7 +166,7 @@ static Bool SW_check_soil_properties( ) { int k; - RealD fval = 0; + double fval = 0; char *errtype = NULL; Bool res = swTRUE; @@ -272,7 +274,7 @@ static double lower_limit_of_theta_min( @brief User-input based minimum volumetric water content This function returns minimum soil water content `theta_min` determined -by user input via #SW_SITE._SWCMinVal as +by user input via #SW_SITE.SWCMinVal as * a fixed VWC value, * a fixed SWP value, or * a realistic lower limit from `lower_limit_of_theta_min()`, @@ -284,7 +286,7 @@ by user input via #SW_SITE._SWCMinVal as (independently of the selected SWRC). @param[in] ui_sm_min User input of requested minimum soil moisture, - see _SWCMinVal + see SWCMinVal @param[in] gravel Coarse fragments (> 2 mm; e.g., gravel) of the whole soil [m3/m3] @param[in] width Soil layer width [cm] @@ -294,7 +296,7 @@ by user input via #SW_SITE._SWCMinVal as @param[in] swrc_type Identification number of selected SWRC @param[in] *swrcp Vector of SWRC parameters @param[in] legacy_mode If true then legacy behavior (see details) -@param[in] _SWCMinVal Lower bound on swc. +@param[in] SWCMinVal Lower bound on swc. @return Minimum volumetric water content of the matric soil [cm / cm] */ @@ -308,10 +310,11 @@ static double ui_theta_min( unsigned int swrc_type, double *swrcp, Bool legacy_mode, - RealD _SWCMinVal, + double SWCMinVal, LOG_INFO *LogInfo ) { - double vwc_min = SW_MISSING, tmp_vwcmin; + double vwc_min = SW_MISSING; + double tmp_vwcmin; if (LT(ui_sm_min, 0.0)) { /* user input: request to estimate minimum theta */ @@ -339,17 +342,17 @@ static double ui_theta_min( } } - } else if (GE(_SWCMinVal, 1.0)) { - /* user input: fixed (matric) SWP value; unit(_SWCMinVal) == -bar */ + } else if (GE(SWCMinVal, 1.0)) { + /* user input: fixed (matric) SWP value; unit(SWCMinVal) == -bar */ vwc_min = SWRC_SWPtoSWC( - _SWCMinVal, swrc_type, swrcp, gravel, width, LOGERROR, LogInfo + SWCMinVal, swrc_type, swrcp, gravel, width, LOGERROR, LogInfo ) / ((1. - gravel) * width); } else { - /* user input: fixed matric VWC; unit(_SWCMinVal) == cm/cm */ - vwc_min = _SWCMinVal / width; + /* user input: fixed matric VWC; unit(SWCMinVal) == cm/cm */ + vwc_min = SWCMinVal / width; } return vwc_min; @@ -436,12 +439,9 @@ void SWRC_PTF_estimate_parameters( ) { /* Initialize swrcp[] to 0 */ - memset(swrcp, 0., SWRC_PARAM_NMAX * sizeof(swrcp[0])); - - if (ptf_type == sw_Cosby1984AndOthers) { - SWRC_PTF_Cosby1984_for_Campbell1974(swrcp, sand, clay); + memset(swrcp, 0, SWRC_PARAM_NMAX * sizeof(swrcp[0])); - } else if (ptf_type == sw_Cosby1984) { + if (ptf_type == sw_Cosby1984AndOthers || ptf_type == sw_Cosby1984) { SWRC_PTF_Cosby1984_for_Campbell1974(swrcp, sand, clay); } else { @@ -535,7 +535,7 @@ The arguments `ptf_type`, `sand`, and `clay` are utilized only if */ double SW_swcBulk_saturated( unsigned int swrc_type, - double *swrcp, + const double *swrcp, double gravel, double width, unsigned int ptf_type, @@ -601,11 +601,11 @@ are utilized only in legacy mode, i.e., `ptf` equal to @param[in] width Soil layer width [cm] @param[in] ptf_type Identification number of selected PTF @param[in] ui_sm_min User input of requested minimum soil moisture, - see #SW_SITE._SWCMinVal + see #SW_SITE.SWCMinVal @param[in] sand Sand content of the matric soil (< 2 mm fraction) [g/g] @param[in] clay Clay content of the matric soil (< 2 mm fraction) [g/g] @param[in] swcBulk_sat Saturated water content of the bulk soil [cm] -@param[in] _SWCMinVal Lower bound on swc. +@param[in] SWCMinVal Lower bound on swc. @param[out] LogInfo Holds information on warnings and errors @return Minimum water content of the bulk soil [cm] @@ -620,10 +620,11 @@ double SW_swcBulk_minimum( double sand, double clay, double swcBulk_sat, - RealD _SWCMinVal, + double SWCMinVal, LOG_INFO *LogInfo ) { - double theta_min_sim, theta_min_theoretical = SW_MISSING; + double theta_min_sim; + double theta_min_theoretical = SW_MISSING; /* `theta_min` based on theoretical SWRC */ switch (swrc_type) { @@ -664,7 +665,7 @@ double SW_swcBulk_minimum( // test: // error: "no known conversion from 'bool' to 'Bool'" ptf_type == sw_Cosby1984AndOthers ? swTRUE : swFALSE, - _SWCMinVal, + SWCMinVal, LogInfo ); @@ -1025,7 +1026,11 @@ Bool SWRC_check_parameters_for_FXW(double *swrcp, LOG_INFO *LogInfo) { void PTF_Saxton2006( double *theta_sat, double sand, double clay, LOG_INFO *LogInfo ) { - double OM = 0., theta_33, theta_33t, theta_S33, theta_S33t; + double OM = 0.; + double theta_33; + double theta_33t; + double theta_S33; + double theta_S33t; /* Eq. 2: 33 kPa moisture */ theta_33t = +0.299 - 0.251 * sand + 0.195 * clay + 0.011 * OM + @@ -1166,7 +1171,7 @@ Based on equation 20 from Saxton. @cite Saxton2006. Similarly, estimate soil bulk density from `theta_sat` with `2.65 * (1. - theta_sat * (1. - fractionGravel))`. */ -RealD calculate_soilBulkDensity(RealD matricDensity, RealD fractionGravel) { +double calculate_soilBulkDensity(double matricDensity, double fractionGravel) { return matricDensity * (1. - fractionGravel) + fractionGravel * 2.65; } @@ -1175,8 +1180,8 @@ RealD calculate_soilBulkDensity(RealD matricDensity, RealD fractionGravel) { Based on equation 20 from Saxton. @cite Saxton2006 */ -RealD calculate_soilMatricDensity( - RealD bulkDensity, RealD fractionGravel, LOG_INFO *LogInfo +double calculate_soilMatricDensity( + double bulkDensity, double fractionGravel, LOG_INFO *LogInfo ) { double res; @@ -1211,8 +1216,9 @@ The count stops at first layer with 0. about every soil layer in the simulation @param[in] n_layers Number of layers of soil within the simulation run */ -LyrIndex nlayers_bsevap(RealD *evap_coeff, LyrIndex n_layers) { - LyrIndex s, n = 0; +LyrIndex nlayers_bsevap(double *evap_coeff, LyrIndex n_layers) { + LyrIndex s; + LyrIndex n = 0; ForEachSoilLayer(s, n_layers) { if (GT(evap_coeff[s], 0.0)) { @@ -1238,7 +1244,7 @@ The count stops at first layer with 0 per vegetation type. void nlayers_vegroots( LyrIndex n_layers, LyrIndex n_transp_lyrs[], - RealD transp_coeff[][MAX_LAYERS] + double transp_coeff[][MAX_LAYERS] ) { LyrIndex s; int k; @@ -1312,16 +1318,25 @@ void SW_SIT_read( /* 5-Feb-2002 (cwb) Removed rgntop requirement in * transpiration regions section of input */ - FILE *f; - int lineno = 0, x; - int rgnlow; /* lower layer of region */ - int region; /* transp region definition number */ #ifdef SWDEBUG int debug = 0; #endif + + FILE *f; + int lineno = 0; + int x; + int rgnlow = 0; /* lower layer of region */ + int region = 0; /* transp region definition number */ LyrIndex r; Bool too_many_regions = swFALSE; char inbuf[MAX_FILENAMESIZE]; + int intRes = 0; + int resSNP; + double doubleRes = 0.; + char rgnStr[2][10] = {{'\0'}}; + + Bool doDoubleConv; + Bool strLine; /* note that Files.read() must be called prior to this. */ char *MyFileName = InFiles[eSite]; @@ -1332,108 +1347,128 @@ void SW_SIT_read( } while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { + + strLine = (Bool) (lineno == 35 || lineno == 37 || lineno == 38); + + if (!strLine && lineno <= 38) { + /* Check to see if the line number contains a double or integer + * value */ + doDoubleConv = (Bool) ((lineno >= 0 && lineno <= 2) || + (lineno >= 5 && lineno <= 31)); + + if (doDoubleConv) { + doubleRes = sw_strtod(inbuf, MyFileName, LogInfo); + } else { + intRes = sw_strtoi(inbuf, MyFileName, LogInfo); + } + + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (lineno) { case 0: - SW_Site->_SWCMinVal = atof(inbuf); + SW_Site->SWCMinVal = doubleRes; break; case 1: - SW_Site->_SWCInitVal = atof(inbuf); + SW_Site->SWCInitVal = doubleRes; break; case 2: - SW_Site->_SWCWetVal = atof(inbuf); + SW_Site->SWCWetVal = doubleRes; break; case 3: - SW_Site->reset_yr = itob(atoi(inbuf)); + SW_Site->reset_yr = itob(intRes); break; case 4: - SW_Site->deepdrain = itob(atoi(inbuf)); + SW_Site->deepdrain = itob(intRes); break; case 5: - SW_Site->pet_scale = atof(inbuf); + SW_Site->pet_scale = doubleRes; break; case 6: - SW_Site->percentRunoff = atof(inbuf); + SW_Site->percentRunoff = doubleRes; break; case 7: - SW_Site->percentRunon = atof(inbuf); + SW_Site->percentRunon = doubleRes; break; case 8: - SW_Site->TminAccu2 = atof(inbuf); + SW_Site->TminAccu2 = doubleRes; break; case 9: - SW_Site->TmaxCrit = atof(inbuf); + SW_Site->TmaxCrit = doubleRes; break; case 10: - SW_Site->lambdasnow = atof(inbuf); + SW_Site->lambdasnow = doubleRes; break; case 11: - SW_Site->RmeltMin = atof(inbuf); + SW_Site->RmeltMin = doubleRes; break; case 12: - SW_Site->RmeltMax = atof(inbuf); + SW_Site->RmeltMax = doubleRes; break; case 13: - SW_Site->slow_drain_coeff = atof(inbuf); + SW_Site->slow_drain_coeff = doubleRes; break; case 14: - SW_Site->evap.xinflec = atof(inbuf); + SW_Site->evap.xinflec = doubleRes; break; case 15: - SW_Site->evap.slope = atof(inbuf); + SW_Site->evap.slope = doubleRes; break; case 16: - SW_Site->evap.yinflec = atof(inbuf); + SW_Site->evap.yinflec = doubleRes; break; case 17: - SW_Site->evap.range = atof(inbuf); + SW_Site->evap.range = doubleRes; break; case 18: - SW_Site->transp.xinflec = atof(inbuf); + SW_Site->transp.xinflec = doubleRes; break; case 19: - SW_Site->transp.slope = atof(inbuf); + SW_Site->transp.slope = doubleRes; break; case 20: - SW_Site->transp.yinflec = atof(inbuf); + SW_Site->transp.yinflec = doubleRes; break; case 21: - SW_Site->transp.range = atof(inbuf); + SW_Site->transp.range = doubleRes; break; case 22: - SW_Site->bmLimiter = atof(inbuf); + SW_Site->bmLimiter = doubleRes; break; case 23: - SW_Site->t1Param1 = atof(inbuf); + SW_Site->t1Param1 = doubleRes; break; case 24: - SW_Site->t1Param2 = atof(inbuf); + SW_Site->t1Param2 = doubleRes; break; case 25: - SW_Site->t1Param3 = atof(inbuf); + SW_Site->t1Param3 = doubleRes; break; case 26: - SW_Site->csParam1 = atof(inbuf); + SW_Site->csParam1 = doubleRes; break; case 27: - SW_Site->csParam2 = atof(inbuf); + SW_Site->csParam2 = doubleRes; break; case 28: - SW_Site->shParam = atof(inbuf); + SW_Site->shParam = doubleRes; break; case 29: - SW_Site->Tsoil_constant = atof(inbuf); + SW_Site->Tsoil_constant = doubleRes; break; case 30: - SW_Site->stDeltaX = atof(inbuf); + SW_Site->stDeltaX = doubleRes; break; case 31: - SW_Site->stMaxDepth = atof(inbuf); + SW_Site->stMaxDepth = doubleRes; break; case 32: - SW_Site->use_soil_temp = itob(atoi(inbuf)); + SW_Site->use_soil_temp = itob(intRes); break; case 33: - SW_Carbon->use_bio_mult = itob(atoi(inbuf)); + SW_Carbon->use_bio_mult = itob(intRes); #ifdef SWDEBUG if (debug) { sw_printf( @@ -1444,7 +1479,7 @@ void SW_SIT_read( #endif break; case 34: - SW_Carbon->use_wue_mult = itob(atoi(inbuf)); + SW_Carbon->use_wue_mult = itob(intRes); #ifdef SWDEBUG if (debug) { sw_printf( @@ -1455,7 +1490,19 @@ void SW_SIT_read( #endif break; case 35: - strcpy(SW_Carbon->scenario, inbuf); + resSNP = snprintf( + SW_Carbon->scenario, sizeof SW_Carbon->scenario, "%s", inbuf + ); + if (resSNP < 0 || + (unsigned) resSNP >= (sizeof SW_Carbon->scenario)) { + LogError( + LogInfo, + LOGERROR, + "Atmospheric [CO2] scenario name is too long: '%s'.", + inbuf + ); + goto closeFile; + } #ifdef SWDEBUG if (debug) { sw_printf( @@ -1465,23 +1512,46 @@ void SW_SIT_read( #endif break; case 36: - SW_Site->type_soilDensityInput = atoi(inbuf); + SW_Site->type_soilDensityInput = intRes; break; case 37: - strcpy(SW_Site->site_swrc_name, inbuf); + resSNP = snprintf( + SW_Site->site_swrc_name, + sizeof SW_Site->site_swrc_name, + "%s", + inbuf + ); + if (resSNP < 0 || + (unsigned) resSNP >= (sizeof SW_Site->site_swrc_name)) { + LogError( + LogInfo, LOGERROR, "SWRC name is too long: '%s'.", inbuf + ); + goto closeFile; + } SW_Site->site_swrc_type = encode_str2swrc(SW_Site->site_swrc_name, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } break; case 38: - strcpy(SW_Site->site_ptf_name, inbuf); + resSNP = snprintf( + SW_Site->site_ptf_name, + sizeof SW_Site->site_ptf_name, + "%s", + inbuf + ); + if (resSNP < 0 || + (unsigned) resSNP >= (sizeof SW_Site->site_ptf_name)) { + LogError( + LogInfo, LOGERROR, "PTF name is too long: '%s'.", inbuf + ); + goto closeFile; + } SW_Site->site_ptf_type = encode_str2ptf(SW_Site->site_ptf_name); break; case 39: - SW_Site->site_has_swrcp = itob(atoi(inbuf)); + SW_Site->site_has_swrcp = itob(intRes); break; default: @@ -1493,9 +1563,21 @@ void SW_SIT_read( too_many_regions = swTRUE; goto Label_End_Read; } - x = sscanf(inbuf, "%d %d", ®ion, &rgnlow); + x = sscanf(inbuf, "%9s %9s", rgnStr[0], rgnStr[1]); + + if (x == 2) { + region = sw_strtoi(rgnStr[0], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + + rgnlow = sw_strtoi(rgnStr[1], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + if (x < 2 || region < 1 || rgnlow < 1) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1503,9 +1585,9 @@ void SW_SIT_read( MyFileName, lineno ); - return; // Exit function prematurely due to error + goto closeFile; } - SW_Site->_TranspRgnBounds[region - 1] = (LyrIndex) (rgnlow - 1); + SW_Site->TranspRgnBounds[region - 1] = (LyrIndex) (rgnlow - 1); SW_Site->n_transp_rgn++; } @@ -1514,8 +1596,6 @@ void SW_SIT_read( Label_End_Read: - CloseFile(&f, LogInfo); - if (LT(SW_Site->percentRunoff, 0.) || GT(SW_Site->percentRunoff, 1.)) { LogError( LogInfo, @@ -1525,7 +1605,7 @@ void SW_SIT_read( MyFileName, SW_Site->percentRunoff ); - return; // Exit function prematurely due to error + goto closeFile; } if (LT(SW_Site->percentRunon, 0.)) { @@ -1537,7 +1617,7 @@ void SW_SIT_read( MyFileName, SW_Site->percentRunon ); - return; // Exit function prematurely due to error + goto closeFile; } if (too_many_regions) { @@ -1550,21 +1630,23 @@ void SW_SIT_read( SW_Site->n_transp_rgn, MAX_TRANSP_REGIONS ); - return; // Exit function prematurely due to error + goto closeFile; } /* check for any discontinuities (reversals) in the transpiration regions */ for (r = 1; r < SW_Site->n_transp_rgn; r++) { - if (SW_Site->_TranspRgnBounds[r - 1] >= SW_Site->_TranspRgnBounds[r]) { + if (SW_Site->TranspRgnBounds[r - 1] >= SW_Site->TranspRgnBounds[r]) { LogError( LogInfo, LOGERROR, "%s : Discontinuity/reversal in transpiration regions.\n", InFiles[eSite] ); - return; // Exit function prematurely due to error + goto closeFile; } } + +closeFile: { CloseFile(&f, LogInfo); } } /** Reads soil layers and soil properties from input file @@ -1581,10 +1663,36 @@ void SW_LYR_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { FILE *f; LyrIndex lyrno; - int x, k; - RealF dmin = 0.0, dmax, evco, trco_veg[NVEGTYPES], psand, pclay, - soildensity, imperm, soiltemp, f_gravel; + int x; + int k; + int index; + double dmin = 0.0; + double dmax; + double evco; + double trco_veg[NVEGTYPES]; + double psand; + double pclay; + double soildensity; + double imperm; + double soiltemp; + double f_gravel; char inbuf[MAX_FILENAMESIZE]; + char inDoubleStrs[12][20] = {{'\0'}}; + double *inDoubleVals[] = { + &dmax, + &soildensity, + &f_gravel, + &evco, + &trco_veg[SW_GRASS], + &trco_veg[SW_SHRUB], + &trco_veg[SW_TREES], + &trco_veg[SW_FORBS], + &psand, + &pclay, + &imperm, + &soiltemp + }; + const int numDoubleInStrings = 12; /* note that Files.read() must be called prior to this. */ char *MyFileName = InFiles[eLayers]; @@ -1599,25 +1707,24 @@ void SW_LYR_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { x = sscanf( inbuf, - "%f %f %f %f %f %f %f %f %f %f %f %f", - &dmax, - &soildensity, - &f_gravel, - &evco, - &trco_veg[SW_GRASS], - &trco_veg[SW_SHRUB], - &trco_veg[SW_TREES], - &trco_veg[SW_FORBS], - &psand, - &pclay, - &imperm, - &soiltemp + "%19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s", + inDoubleStrs[0], + inDoubleStrs[1], + inDoubleStrs[2], + inDoubleStrs[3], + inDoubleStrs[4], + inDoubleStrs[5], + inDoubleStrs[6], + inDoubleStrs[7], + inDoubleStrs[8], + inDoubleStrs[9], + inDoubleStrs[10], + inDoubleStrs[11] ); /* Check that we have 12 values per layer */ /* Adjust number if new variables are added */ if (x != 12) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1625,7 +1732,16 @@ void SW_LYR_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { MyFileName, lyrno + 1 ); - return; // Exit function prematurely due to error + goto closeFile; + } + + /* Convert strings to doubles */ + for (index = 0; index < numDoubleInStrings; index++) { + *(inDoubleVals[index]) = + sw_strtod(inDoubleStrs[index], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } } SW_Site->width[lyrno] = dmax - dmin; @@ -1645,7 +1761,6 @@ void SW_LYR_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { SW_Site->avgLyrTempInit[lyrno] = soiltemp; if (lyrno >= MAX_LAYERS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1655,11 +1770,11 @@ void SW_LYR_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { lyrno + 1, MAX_LAYERS ); - return; // Exit function prematurely due to error + goto closeFile; } } - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -1712,27 +1827,28 @@ void set_soillayers( SW_VEGPROD *SW_VegProd, SW_SITE *SW_Site, LyrIndex nlyrs, - RealF *dmax, - RealF *bd, - RealF *f_gravel, - RealF *evco, - RealF *trco_grass, - RealF *trco_shrub, - RealF *trco_tree, - RealF *trco_forb, - RealF *psand, - RealF *pclay, - RealF *imperm, - RealF *soiltemp, + const double *dmax, + const double *bd, + const double *f_gravel, + const double *evco, + const double *trco_grass, + const double *trco_shrub, + const double *trco_tree, + const double *trco_forb, + const double *psand, + const double *pclay, + const double *imperm, + const double *soiltemp, int nRegions, - RealD *regionLowerBounds, + double *regionLowerBounds, LOG_INFO *LogInfo ) { - RealF dmin = 0.0; + double dmin = 0.0; LyrIndex lyrno; - unsigned int i, k; + unsigned int i; + unsigned int k; // De-allocate and delete previous soil layers and reset counters SW_SIT_init_counts(SW_Site); @@ -1763,6 +1879,8 @@ void set_soillayers( case SW_GRASS: SW_Site->transp_coeff[k][lyrno] = trco_grass[i]; break; + default: + break; } } @@ -1796,21 +1914,26 @@ void set_soillayers( @param[out] LogInfo Holds information on warnings and errors @sideeffect - \ref SW_SITE._TranspRgnBounds and \ref SW_SITE.n_transp_rgn will be + \ref SW_SITE.TranspRgnBounds and \ref SW_SITE.n_transp_rgn will be derived from the input and from the soil information. @note - \p nRegions does NOT determine how many regions will be derived. It only defines the size of the \p regionLowerBounds array. For example, if your input parameters are `(4, { 10, 20, 40 })`, but there is a soil layer from - 41 to 60 cm, it will be placed in `_TranspRgnBounds[4]`. + 41 to 60 cm, it will be placed in `TranspRgnBounds[4]`. */ void derive_soilRegions( - SW_SITE *SW_Site, int nRegions, RealD *regionLowerBounds, LOG_INFO *LogInfo + SW_SITE *SW_Site, + unsigned int nRegions, + const double *regionLowerBounds, + LOG_INFO *LogInfo ) { - int i, j; - RealD totalDepth = 0; - LyrIndex layer, UNDEFINED_LAYER = 999; + unsigned int i; + unsigned int j; + double totalDepth = 0; + LyrIndex layer; + LyrIndex UNDEFINED_LAYER = 999; /* ------------- Error checking --------------- */ if (nRegions < 1 || nRegions > MAX_TRANSP_REGIONS) { @@ -1826,7 +1949,7 @@ void derive_soilRegions( /* --------------- Clear out the array ------------------ */ for (i = 0; i < MAX_TRANSP_REGIONS; ++i) { // Setting bounds to a ridiculous number so we know how many get set. - SW_Site->_TranspRgnBounds[i] = UNDEFINED_LAYER; + SW_Site->TranspRgnBounds[i] = UNDEFINED_LAYER; } /* ----------------- Derive Regions ------------------- */ @@ -1834,13 +1957,13 @@ void derive_soilRegions( layer = 0; // SW_Site.lyr is base0-indexed totalDepth = 0; for (i = 0; i < nRegions; ++i) { - SW_Site->_TranspRgnBounds[i] = layer; + SW_Site->TranspRgnBounds[i] = layer; // Find the layer that pushes us out of the region. // It becomes the bound. while (totalDepth < regionLowerBounds[i] && layer < SW_Site->n_layers && sum_across_vegtypes(SW_Site->transp_coeff, layer)) { totalDepth += SW_Site->width[layer]; - SW_Site->_TranspRgnBounds[i] = layer; + SW_Site->TranspRgnBounds[i] = layer; layer++; } } @@ -1849,19 +1972,18 @@ void derive_soilRegions( for (i = 0; i < nRegions - 1; ++i) { // If there is a duplicate bound we will remove it by left shifting the // array, overwriting the duplicate. - if (SW_Site->_TranspRgnBounds[i] == SW_Site->_TranspRgnBounds[i + 1]) { + if (SW_Site->TranspRgnBounds[i] == SW_Site->TranspRgnBounds[i + 1]) { for (j = i + 1; j < nRegions - 1; ++j) { - SW_Site->_TranspRgnBounds[j] = SW_Site->_TranspRgnBounds[j + 1]; + SW_Site->TranspRgnBounds[j] = SW_Site->TranspRgnBounds[j + 1]; } - SW_Site->_TranspRgnBounds[MAX_TRANSP_REGIONS - 1] = UNDEFINED_LAYER; + SW_Site->TranspRgnBounds[MAX_TRANSP_REGIONS - 1] = UNDEFINED_LAYER; } } /* -------------- Derive n_transp_rgn --------------- */ SW_Site->n_transp_rgn = 0; while (SW_Site->n_transp_rgn < MAX_TRANSP_REGIONS && - SW_Site->_TranspRgnBounds[SW_Site->n_transp_rgn] != UNDEFINED_LAYER - ) { + SW_Site->TranspRgnBounds[SW_Site->n_transp_rgn] != UNDEFINED_LAYER) { SW_Site->n_transp_rgn++; } } @@ -1881,10 +2003,14 @@ void SW_SWRC_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { } FILE *f; - LyrIndex lyrno = 0, k; + LyrIndex lyrno = 0; + LyrIndex k; int x; - RealF tmp_swrcp[SWRC_PARAM_NMAX]; + int index; + double tmp_swrcp[SWRC_PARAM_NMAX]; char inbuf[MAX_FILENAMESIZE]; + char swrcpDoubleStrs[6][20] = {{'\0'}}; + const int numDoubleInStrings = 6; /* note that Files.read() must be called prior to this. */ char *MyFileName = InFiles[eSWRCp]; @@ -1897,13 +2023,13 @@ void SW_SWRC_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { x = sscanf( inbuf, - "%f %f %f %f %f %f", - &tmp_swrcp[0], - &tmp_swrcp[1], - &tmp_swrcp[2], - &tmp_swrcp[3], - &tmp_swrcp[4], - &tmp_swrcp[5] + "%19s %19s %19s %19s %19s %19s", + swrcpDoubleStrs[0], + swrcpDoubleStrs[1], + swrcpDoubleStrs[2], + swrcpDoubleStrs[3], + swrcpDoubleStrs[4], + swrcpDoubleStrs[5] ); /* Note: `SW_SIT_init_run()` will call function to check for valid @@ -1911,7 +2037,6 @@ void SW_SWRC_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { /* Check that we have n = `SWRC_PARAM_NMAX` values per layer */ if (x != SWRC_PARAM_NMAX) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1920,12 +2045,20 @@ void SW_SWRC_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { x, SWRC_PARAM_NMAX ); - return; // Exit function prematurely due to error + goto closeFile; + } + + /* Convert strings to doubles */ + for (index = 0; index < numDoubleInStrings; index++) { + tmp_swrcp[index] = + sw_strtod(swrcpDoubleStrs[index], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } } /* Check that we are within `SW_Site.n_layers` */ if (lyrno >= SW_Site->n_layers) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1935,7 +2068,7 @@ void SW_SWRC_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { lyrno + 1, SW_Site->n_layers ); - return; // Exit function prematurely due to error + goto closeFile; } /* Copy values into structure */ @@ -1946,7 +2079,7 @@ void SW_SWRC_read(SW_SITE *SW_Site, char *InFiles[], LOG_INFO *LogInfo) { lyrno++; } - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -1981,15 +2114,21 @@ void SW_SIT_init_run( /* 5-Mar-2002 (cwb) added normalization for ev and tr coefficients */ /* 1-Oct-03 (cwb) removed sum_evap_coeff and sum_transp_coeff */ - LyrIndex s, r, curregion; - int k, flagswpcrit = 0; - RealD evsum = 0., trsum_veg[NVEGTYPES] = {0.}, tmp; - double acc = 0.0; - #ifdef SWDEBUG int debug = 0; #endif + LyrIndex s; + LyrIndex r; + LyrIndex curregion; + int k; + int flagswpcrit = 0; + double evsum = 0.; + double trsum_veg[NVEGTYPES] = {0.}; + double tmp; + double acc = 0.0; + double tmp_stNRGR; + /* Determine number of layers with potential for bare-soil evaporation and transpiration */ @@ -2178,11 +2317,11 @@ void SW_SIT_init_run( SW_Site->fractionVolBulk_gravel[s], SW_Site->width[s], SW_Site->ptf_type[s], - SW_Site->_SWCMinVal, + SW_Site->SWCMinVal, SW_Site->fractionWeightMatric_sand[s], SW_Site->fractionWeightMatric_clay[s], SW_Site->swcBulk_saturated[s], - SW_Site->_SWCMinVal, + SW_Site->SWCMinVal, LogInfo ); if (LogInfo->stopRun) { @@ -2192,18 +2331,18 @@ void SW_SIT_init_run( /* Calculate wet limit of SWC for what inputs defined as wet */ SW_Site->swcBulk_wet[s] = - GE(SW_Site->_SWCWetVal, 1.0) ? - SW_SWRC_SWPtoSWC(SW_Site->_SWCWetVal, SW_Site, s, LogInfo) : - SW_Site->_SWCWetVal * SW_Site->width[s]; + GE(SW_Site->SWCWetVal, 1.0) ? + SW_SWRC_SWPtoSWC(SW_Site->SWCWetVal, SW_Site, s, LogInfo) : + SW_Site->SWCWetVal * SW_Site->width[s]; if (LogInfo->stopRun) { return; // Exit function prematurely due to error } /* Calculate initial SWC based on inputs */ SW_Site->swcBulk_init[s] = - GE(SW_Site->_SWCInitVal, 1.0) ? - SW_SWRC_SWPtoSWC(SW_Site->_SWCInitVal, SW_Site, s, LogInfo) : - SW_Site->_SWCInitVal * SW_Site->width[s]; + GE(SW_Site->SWCInitVal, 1.0) ? + SW_SWRC_SWPtoSWC(SW_Site->SWCInitVal, SW_Site, s, LogInfo) : + SW_Site->SWCInitVal * SW_Site->width[s]; if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -2372,7 +2511,7 @@ void SW_SIT_init_run( * base1 but s is base0.*/ curregion = 0; ForEachTranspRegion(r, SW_Site->n_transp_rgn) { - if (s < SW_Site->_TranspRgnBounds[r]) { + if (s < SW_Site->TranspRgnBounds[r]) { if (ZRO(SW_Site->transp_coeff[k][s])) { break; /* end of transpiring layers */ } @@ -2381,7 +2520,7 @@ void SW_SIT_init_run( } } - if (curregion || SW_Site->_TranspRgnBounds[curregion] == 0) { + if (curregion || SW_Site->TranspRgnBounds[curregion] == 0) { SW_Site->my_transp_rgn[k][s] = curregion; SW_Site->n_transp_lyrs[k] = MAX(SW_Site->n_transp_lyrs[k], s); @@ -2513,7 +2652,13 @@ void SW_SIT_init_run( // getting the number of regressions, for use in the soil_temperature // function - SW_Site->stNRGR = (SW_Site->stMaxDepth / SW_Site->stDeltaX) - 1; + tmp_stNRGR = (SW_Site->stMaxDepth / SW_Site->stDeltaX); + if (tmp_stNRGR > (double) UINT_MAX) { + SW_Site->stNRGR = MAX_ST_RGR + 1; + } else { + SW_Site->stNRGR = (unsigned int) tmp_stNRGR - 1; + } + Bool too_many_RGR = (Bool) (SW_Site->stNRGR + 1 >= MAX_ST_RGR); if (!EQ(fmod(SW_Site->stMaxDepth, SW_Site->stDeltaX), 0.0) || @@ -2574,7 +2719,7 @@ void SW_SIT_init_counts(SW_SITE *SW_Site) { @param[in] SW_Model Struct of type SW_MODEL holding basic time information about the simulation */ -void _echo_inputs(SW_SITE *SW_Site, SW_MODEL *SW_Model) { +void echo_inputs(SW_SITE *SW_Site, SW_MODEL *SW_Model) { /* =================================================== */ LyrIndex i; LOG_INFO LogInfo; diff --git a/src/SW_Sky.c b/src/SW_Sky.c index 500f26d7a..f29b30dba 100644 --- a/src/SW_Sky.c +++ b/src/SW_Sky.c @@ -37,7 +37,7 @@ /* --------------------------------------------------- */ #include "include/SW_Sky.h" // for SW_SKY_new_year, SW_SKY_read #include "include/filefuncs.h" // for CloseFile, GetALine, LogError -#include "include/generic.h" // for RealD, Bool, LOGERROR, swTRUE +#include "include/generic.h" // for Bool, LOGERROR, swTRUE #include "include/SW_datastructs.h" // for LOG_INFO, SW_MODEL, SW_SKY #include "include/SW_Defines.h" // for MAX_FILENAMESIZE, MAX_MONTHS #include "include/SW_Files.h" // for eSky @@ -66,9 +66,16 @@ void SW_SKY_read(char *InFiles[], SW_SKY *SW_Sky, LOG_INFO *LogInfo) { * and cloud cover from line 3 instead -> SW_SKY_read() is now reading as * the input files are formatted */ + FILE *f; - int lineno = 0, x = 0; - char *MyFileName, inbuf[MAX_FILENAMESIZE]; + int lineno = 0; + int x = 0; + int k; + int index; + double tmp[MAX_MONTHS]; + char *MyFileName; + char inbuf[MAX_FILENAMESIZE]; + char tmpStrs[MAX_MONTHS][20] = {{'\0'}}; MyFileName = InFiles[eSky]; f = OpenFile(MyFileName, "r", LogInfo); @@ -77,116 +84,85 @@ void SW_SKY_read(char *InFiles[], SW_SKY *SW_Sky, LOG_INFO *LogInfo) { } while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { + x = sscanf( + inbuf, + "%19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s %19s", + tmpStrs[0], + tmpStrs[1], + tmpStrs[2], + tmpStrs[3], + tmpStrs[4], + tmpStrs[5], + tmpStrs[6], + tmpStrs[7], + tmpStrs[8], + tmpStrs[9], + tmpStrs[10], + tmpStrs[11] + ); + + if (x != 12) { + LogError( + LogInfo, + LOGERROR, + "%s : invalid record %d.\n", + MyFileName, + lineno + ); + goto closeFile; + } + + for (index = 0; index < MAX_MONTHS; index++) { + tmp[index] = sw_strtod(tmpStrs[index], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (lineno) { case 0: - x = sscanf( - inbuf, - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &SW_Sky->cloudcov[0], - &SW_Sky->cloudcov[1], - &SW_Sky->cloudcov[2], - &SW_Sky->cloudcov[3], - &SW_Sky->cloudcov[4], - &SW_Sky->cloudcov[5], - &SW_Sky->cloudcov[6], - &SW_Sky->cloudcov[7], - &SW_Sky->cloudcov[8], - &SW_Sky->cloudcov[9], - &SW_Sky->cloudcov[10], - &SW_Sky->cloudcov[11] - ); + for (k = 0; k < MAX_MONTHS; k++) { + SW_Sky->cloudcov[k] = tmp[k]; + } break; case 1: - x = sscanf( - inbuf, - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &SW_Sky->windspeed[0], - &SW_Sky->windspeed[1], - &SW_Sky->windspeed[2], - &SW_Sky->windspeed[3], - &SW_Sky->windspeed[4], - &SW_Sky->windspeed[5], - &SW_Sky->windspeed[6], - &SW_Sky->windspeed[7], - &SW_Sky->windspeed[8], - &SW_Sky->windspeed[9], - &SW_Sky->windspeed[10], - &SW_Sky->windspeed[11] - ); + for (k = 0; k < MAX_MONTHS; k++) { + SW_Sky->windspeed[k] = tmp[k]; + } break; case 2: - x = sscanf( - inbuf, - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &SW_Sky->r_humidity[0], - &SW_Sky->r_humidity[1], - &SW_Sky->r_humidity[2], - &SW_Sky->r_humidity[3], - &SW_Sky->r_humidity[4], - &SW_Sky->r_humidity[5], - &SW_Sky->r_humidity[6], - &SW_Sky->r_humidity[7], - &SW_Sky->r_humidity[8], - &SW_Sky->r_humidity[9], - &SW_Sky->r_humidity[10], - &SW_Sky->r_humidity[11] - ); + for (k = 0; k < MAX_MONTHS; k++) { + SW_Sky->r_humidity[k] = tmp[k]; + } break; case 3: - x = sscanf( - inbuf, - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &SW_Sky->snow_density[0], - &SW_Sky->snow_density[1], - &SW_Sky->snow_density[2], - &SW_Sky->snow_density[3], - &SW_Sky->snow_density[4], - &SW_Sky->snow_density[5], - &SW_Sky->snow_density[6], - &SW_Sky->snow_density[7], - &SW_Sky->snow_density[8], - &SW_Sky->snow_density[9], - &SW_Sky->snow_density[10], - &SW_Sky->snow_density[11] - ); + for (k = 0; k < MAX_MONTHS; k++) { + SW_Sky->snow_density[k] = tmp[k]; + } break; case 4: - x = sscanf( - inbuf, - "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &SW_Sky->n_rain_per_day[0], - &SW_Sky->n_rain_per_day[1], - &SW_Sky->n_rain_per_day[2], - &SW_Sky->n_rain_per_day[3], - &SW_Sky->n_rain_per_day[4], - &SW_Sky->n_rain_per_day[5], - &SW_Sky->n_rain_per_day[6], - &SW_Sky->n_rain_per_day[7], - &SW_Sky->n_rain_per_day[8], - &SW_Sky->n_rain_per_day[9], - &SW_Sky->n_rain_per_day[10], - &SW_Sky->n_rain_per_day[11] - ); + for (k = 0; k < MAX_MONTHS; k++) { + SW_Sky->n_rain_per_day[k] = tmp[k]; + } break; - } - if (x < 12) { - CloseFile(&f, LogInfo); + default: LogError( LogInfo, LOGERROR, - "%s : invalid record %d.\n", + "%s : too many rows %d.\n", MyFileName, lineno ); - return; // Exit function prematurely due to error + goto closeFile; + + break; } - x = 0; lineno++; } - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -203,8 +179,8 @@ prior to this function. */ void SW_SKY_new_year( SW_MODEL *SW_Model, - RealD snow_density[MAX_MONTHS], - RealD snow_density_daily[MAX_MONTHS] + double snow_density[MAX_MONTHS], + double snow_density_daily[MAX_MONTHS] ) { Bool interpAsBase1 = swTRUE; diff --git a/src/SW_SoilWater.c b/src/SW_SoilWater.c index 33434389d..9f7ebcade 100644 --- a/src/SW_SoilWater.c +++ b/src/SW_SoilWater.c @@ -73,7 +73,7 @@ #include "include/SW_SoilWater.h" // for FXW_h0, FXW_hr, SWRC_SWCtoSWP #include "include/filefuncs.h" // for LogError, CloseFile, GetALine -#include "include/generic.h" // for RealD, LOGERROR, GT, LT, fmax +#include "include/generic.h" // for LOGERROR, GT, LT, fmax #include "include/myMemory.h" // for Mem_Calloc, Str_Dup #include "include/SW_datastructs.h" // for LOG_INFO, SW_SOILWAT, SW_SITE #include "include/SW_Defines.h" // for NVEGTYPES, LyrIndex, MAX_LAYERS @@ -84,7 +84,7 @@ #include "include/Times.h" // for yearto4digit #include // for fabs, pow, log, ceil, copysign #include // for NULL, FILE, sscanf, snprintf -#include // for atoi, free +#include // for free #include // for memset @@ -97,9 +97,9 @@ /* Local Function Definitions */ /* --------------------------------------------------- */ -static void _clear_hist( - RealD SoilWat_hist_swc[][MAX_LAYERS], - RealD SoilWat_hist_std_err[][MAX_LAYERS] +static void clear_hist( + double SoilWat_hist_swc[][MAX_LAYERS], + double SoilWat_hist_std_err[][MAX_LAYERS] ) { TimeInt d; LyrIndex z; @@ -111,7 +111,7 @@ static void _clear_hist( } } -static void _reset_swc(SW_SOILWAT *SW_SoilWat, SW_SITE *SW_Site) { +static void reset_swc(SW_SOILWAT *SW_SoilWat, SW_SITE *SW_Site) { LyrIndex lyr; /* reset swc */ @@ -140,7 +140,10 @@ use `SWRC_SWPtoSWC_FXW()` instead. @return Volumetric soil water content of the matric soil [cm / cm] */ static double FXW_phi_to_theta(double phi, double *swrcp) { - double tmp, res, S_e, C_f; + double tmp; + double res; + double S_e; + double C_f; if (GE(phi, FXW_h0)) { res = 0.; @@ -198,17 +201,35 @@ here](https://en.wikipedia.org/wiki/ITP_method) */ static double itp_FXW_for_phi(double theta, double *swrcp, LOG_INFO *LogInfo) { - double tol2 = 2e-9, // tolerance convergence - a = 0., // lower bound of bracket: a < b && f(a) < 0 - b = FXW_h0, // upper bound of bracket: b > a && f(b) > 0 - diff_ba = FXW_h0, diff_hf, x_f, x_t, x_itp, y_a, y_b, y_itp, k1, k2, - x_half, r, delta, sigma, phi; - int j = 0, n0, n_max; - #ifdef SWDEBUG short debug = 0; #endif + // tol2: tolerance convergence + double tol2 = 2e-9; + // a: lower bound of bracket: a < b && f(a) < 0 + double a = 0.; + // b: upper bound of bracket: b > a && f(b) > 0 + double b = FXW_h0; + double diff_ba = FXW_h0; + double diff_hf; + double x_f; + double x_t; + double x_itp; + double y_a; + double y_b; + double y_itp; + double k1; + double k2; + double x_half; + double r; + double delta; + double sigma; + double phi; + int j = 0; + int n0; + int n_max; + // Evaluate at starting bracket (and checks) y_a = theta - FXW_phi_to_theta(a, swrcp); @@ -216,7 +237,7 @@ static double itp_FXW_for_phi(double theta, double *swrcp, LOG_INFO *LogInfo) { // Set hyper-parameters - k1 = 3.174603e-08; // 0 < k1 = 0.2 / (b - a) < inf + // k1 = 3.174603e-08; // 0 < k1 = 0.2 / (b - a) < inf /* k1 = 2. converges in about 31-33 iterations k1 = 0.2 converges in 28-30 iterations @@ -378,20 +399,42 @@ static double itp_FXW_for_phi(double theta, double *swrcp, LOG_INFO *LogInfo) { #ifdef SWDEBUG void SW_WaterBalance_Checks(SW_RUN *sw, LOG_INFO *LogInfo) { - IntUS i, k; + LyrIndex i; + IntUS k; int debugi[N_WBCHECKS] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 }; // print output for each check yes/no char flag[16]; - RealD Etotal, Etotalsurf, Etotalint, Eponded, Elitter, Esnow, - Esoil = 0., Eveg = 0., Ttotal = 0., Ttotalj[MAX_LAYERS], - percolationIn[MAX_LAYERS + 1], percolationOut[MAX_LAYERS + 1], - hydraulicRedistribution[MAX_LAYERS], infiltration, deepDrainage, runoff, - runon, snowmelt, rain, arriving_water, intercepted, int_veg_total = 0., - delta_surfaceWater, delta_swc_total = 0., delta_swcj[MAX_LAYERS]; - RealD lhs, rhs, wbtol = 1e-9; - - static RealD surfaceWater_yesterday; + double Etotal; + double Etotalsurf; + double Etotalint; + double Eponded; + double Elitter; + double Esnow; + double Esoil = 0.; + double Eveg = 0.; + double Ttotal = 0.; + double Ttotalj[MAX_LAYERS]; + double percolationIn[MAX_LAYERS + 1]; + double percolationOut[MAX_LAYERS + 1]; + double hydraulicRedistribution[MAX_LAYERS]; + double infiltration; + double deepDrainage; + double runoff; + double runon; + double snowmelt; + double rain; + double arriving_water; + double intercepted; + double int_veg_total = 0.; + double delta_surfaceWater; + double delta_swc_total = 0.; + double delta_swcj[MAX_LAYERS]; + double lhs; + double rhs; + double wbtol = 1e-9; + + static double surfaceWater_yesterday; static Bool debug = swFALSE; LyrIndex n_layers = sw->Site.n_layers; @@ -466,7 +509,7 @@ void SW_WaterBalance_Checks(SW_RUN *sw, LOG_INFO *LogInfo) { } if (debug) { - snprintf( + (void) snprintf( flag, sizeof flag, "WB (%d-%d)", sw->Model.year, sw->Model.doy ); } @@ -837,13 +880,12 @@ water flow, and check if swc is above threshold for "wet" condition. */ void SW_SWC_water_flow(SW_RUN *sw, LOG_INFO *LogInfo) { /* =================================================== */ - - - LyrIndex i; #ifdef SWDEBUG int debug = 0; #endif + LyrIndex i; + /* if there's no swc observation for today, * it shows up as SW_MISSING. The input must * define historical swc for at least the top @@ -934,16 +976,18 @@ use in get_dSWAbulk(). Must be call after `SW_SWC_water_flow()` is executed. /***********************************************************/ void calculate_repartitioned_soilwater( SW_SOILWAT *SW_SoilWat, - RealD swcBulk_atSWPcrit[][MAX_LAYERS], + double swcBulk_atSWPcrit[][MAX_LAYERS], SW_VEGPROD *SW_VegProd, LyrIndex n_layers ) { // this will run for every day of every year LyrIndex i; - RealD val = SW_MISSING; - int j, k; - float curr_crit_val, new_crit_val; + double val = SW_MISSING; + int j; + int k; + double curr_crit_val; + double new_crit_val; ForEachSoilLayer(i, n_layers) { val = SW_SoilWat->swcBulk[Today][i]; @@ -1018,23 +1062,32 @@ the available soilwater of each veg type above so start at bottom move up. */ /***********************************************************/ void get_dSWAbulk( - int i, + unsigned int i, SW_VEGPROD *SW_VegProd, - RealF swa_master[][NVEGTYPES][MAX_LAYERS], - RealF dSWA_repart_sum[][MAX_LAYERS] + double swa_master[][NVEGTYPES][MAX_LAYERS], + double dSWA_repart_sum[][MAX_LAYERS] ) { - int j, kv, curr_vegType, curr_crit_rank_index, kv_veg_type, - prev_crit_veg_type, greater_veg_type; - float crit_val, prev_crit_val, smallestCritVal, vegFractionSum, newFraction; + int j; + int kv; + int curr_vegType; + int curr_crit_rank_index; + int kv_veg_type; + int prev_crit_veg_type; + int greater_veg_type; + double crit_val; + double prev_crit_val; + double smallestCritVal; // set to current veg type fraction value to avoid multiple if loops. should // just need 1 instead of 3 now. - float veg_type_in_use; - float inner_loop_veg_type; // set to inner loop veg type + double veg_type_in_use; + double vegFractionSum; + double newFraction; + double inner_loop_veg_type; // set to inner loop veg type smallestCritVal = SW_VegProd->critSoilWater[SW_VegProd->rank_SWPcrits[0]]; - RealF dSWA_bulk[NVEGTYPES * NVEGTYPES][NVEGTYPES * NVEGTYPES][MAX_LAYERS]; - RealF dSWA_bulk_repartioned[NVEGTYPES * NVEGTYPES][NVEGTYPES * NVEGTYPES] - [MAX_LAYERS]; + double dSWA_bulk[NVEGTYPES * NVEGTYPES][NVEGTYPES * NVEGTYPES][MAX_LAYERS]; + double dSWA_bulk_repartioned[NVEGTYPES * NVEGTYPES][NVEGTYPES * NVEGTYPES] + [MAX_LAYERS]; // need to initialize to 0 for (curr_vegType = 0; curr_vegType < NVEGTYPES; curr_vegType++) { @@ -1218,7 +1271,7 @@ void SW_SWC_end_day(SW_SOILWAT *SW_SoilWat, LyrIndex n_layers) { } void SW_SWC_init_run( - SW_SOILWAT *SW_SoilWat, SW_SITE *SW_Site, RealD *temp_snow + SW_SOILWAT *SW_SoilWat, SW_SITE *SW_Site, double *temp_snow ) { SW_SoilWat->soiltempError = swFALSE; @@ -1229,7 +1282,7 @@ void SW_SWC_init_run( *temp_snow = 0.; // Snow temperature - _reset_swc(SW_SoilWat, SW_Site); + reset_swc(SW_SoilWat, SW_Site); } /** @@ -1249,7 +1302,7 @@ void SW_SWC_new_year( LyrIndex lyr; if (SW_Site->reset_yr) { - _reset_swc(SW_SoilWat, SW_Site); + reset_swc(SW_SoilWat, SW_Site); } else { /* update swc */ @@ -1265,7 +1318,7 @@ void SW_SWC_new_year( /* update historical (measured) values, if needed */ if (SW_SoilWat->hist_use && year >= SW_SoilWat->hist.yr.first) { #ifndef RSOILWAT - _read_swc_hist(&SW_SoilWat->hist, year, LogInfo); + read_swc_hist(&SW_SoilWat->hist, year, LogInfo); #else LogError( LogInfo, @@ -1275,7 +1328,7 @@ void SW_SWC_new_year( if (swFALSE) { // read from disk: - _read_swc_hist(&SW_SoilWat->hist, year, LogInfo); + read_swc_hist(&SW_SoilWat->hist, year, LogInfo); } else { // copy from R memory // onSet_SW_SWC_hist(LogInfo); @@ -1287,7 +1340,7 @@ void SW_SWC_new_year( /** @brief Like all of the other functions, read() reads in the setup parameters. -See _read_swc_hist() for reading historical files. +See read_swc_hist() for reading historical files. @param[in,out] SW_SoilWat Struct of type SW_SOILWAT containing soil water related values @@ -1305,8 +1358,11 @@ void SW_SWC_read( * structure element. */ FILE *f; - int lineno = 0, nitems = 4; + int lineno = 0; + int nitems = 4; char inbuf[MAX_FILENAMESIZE]; + int inBufintRes = 0; + Bool convertInput; char *MyFileName = InFiles[eSoilwat]; f = OpenFile(MyFileName, "r", LogInfo); @@ -1315,31 +1371,46 @@ void SW_SWC_read( } while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { + convertInput = (Bool) (lineno >= 0 && lineno <= 3 && lineno != 1); + + if (convertInput) { + inBufintRes = sw_strtoi(inbuf, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (lineno) { case 0: - SW_SoilWat->hist_use = (atoi(inbuf)) ? swTRUE : swFALSE; + SW_SoilWat->hist_use = (inBufintRes) ? swTRUE : swFALSE; break; case 1: - SW_SoilWat->hist.file_prefix = (char *) Str_Dup(inbuf, LogInfo); + SW_SoilWat->hist.file_prefix = Str_Dup(inbuf, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } break; case 2: - SW_SoilWat->hist.yr.first = yearto4digit(atoi(inbuf)); + SW_SoilWat->hist.yr.first = yearto4digit((TimeInt) inBufintRes); break; case 3: - SW_SoilWat->hist.method = atoi(inbuf); + SW_SoilWat->hist.method = inBufintRes; + break; + default: + LogError( + LogInfo, + LOGERROR, + "SW_SWC_read(): incorrect format of input file '%s'.", + MyFileName + ); + goto closeFile; break; } lineno++; } - CloseFile(&f, LogInfo); - if (!SW_SoilWat->hist_use) { - return; + goto closeFile; } if (lineno < nitems) { LogError( @@ -1348,17 +1419,19 @@ void SW_SWC_read( "%s : Insufficient parameters specified.", MyFileName ); - return; // Exit function prematurely due to error + goto closeFile; } if (SW_SoilWat->hist.method < 1 || SW_SoilWat->hist.method > 2) { LogError( LogInfo, LOGERROR, "%s : Invalid swc adjustment method.", MyFileName ); - return; // Exit function prematurely due to error + goto closeFile; } SW_SoilWat->hist.yr.last = endyr; SW_SoilWat->hist.yr.total = SW_SoilWat->hist.yr.last - SW_SoilWat->hist.yr.first + 1; + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -1372,7 +1445,7 @@ to make the input file name. @param[in] year Four digit number for desired year, measured in years. @param[out] LogInfo Holds information on warnings and errors */ -void _read_swc_hist( +void read_swc_hist( SW_SOILWAT_HIST *SoilWat_hist, TimeInt year, LOG_INFO *LogInfo ) { /* =================================================== */ @@ -1404,16 +1477,32 @@ void _read_swc_hist( * cause problems in the flow model. */ FILE *f; - int x, lyr, recno = 0, doy; - RealF swc, st_err; - char fname[MAX_FILENAMESIZE], inbuf[MAX_FILENAMESIZE]; + int x; + int lyr = 0; + int recno = 0; + int doy = 0; + int index; + int resSNP; + double swc = 0.; + double st_err = 0.; + char fname[MAX_FILENAMESIZE]; + char inbuf[MAX_FILENAMESIZE]; + char varStrs[4][20] = {{'\0'}}; + int *inBufIntVals[] = {&doy, &lyr}; + double *inBufDoubleVals[] = {&swc, &st_err}; + const int numInValsPerType = 2; - snprintf( - fname, MAX_FILENAMESIZE, "%s.%4d", SoilWat_hist->file_prefix, year + resSNP = snprintf( + fname, sizeof fname, "%s.%4d", SoilWat_hist->file_prefix, year ); - if (!FileExists(fname)) { - LogError(LogInfo, LOGWARN, "Historical SWC file %s not found.", fname); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof fname)) { + LogError( + LogInfo, + LOGERROR, + "SWC-hist file name is too long for year = %d", + year + ); return; // Exit function prematurely due to error } @@ -1422,13 +1511,20 @@ void _read_swc_hist( return; // Exit function prematurely due to error } - _clear_hist(SoilWat_hist->swc, SoilWat_hist->std_err); + clear_hist(SoilWat_hist->swc, SoilWat_hist->std_err); while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { recno++; - x = sscanf(inbuf, "%d %d %f %f", &doy, &lyr, &swc, &st_err); + x = sscanf( + inbuf, + "%19s %19s %19s %19s", + varStrs[0], + varStrs[1], + varStrs[2], + varStrs[3] + ); + if (x < 4) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1437,10 +1533,9 @@ void _read_swc_hist( fname, recno ); - return; // Exit function prematurely due to error + goto closeFile; } if (x > 4) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1449,10 +1544,23 @@ void _read_swc_hist( fname, recno ); - return; // Exit function prematurely due to error + goto closeFile; } + + for (index = 0; index < numInValsPerType; index++) { + *(inBufIntVals[index]) = sw_strtoi(varStrs[index], fname, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + + *(inBufDoubleVals[index]) = + sw_strtod(varStrs[index + 2], fname, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + if (doy < 1 || doy > MAX_DAYS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1460,10 +1568,9 @@ void _read_swc_hist( fname, recno ); - return; // Exit function prematurely due to error + goto closeFile; } if (lyr < 1 || lyr > MAX_LAYERS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -1473,13 +1580,14 @@ void _read_swc_hist( MAX_LAYERS, recno ); - return; // Exit function prematurely due to error + goto closeFile; } SoilWat_hist->swc[doy - 1][lyr - 1] = swc; SoilWat_hist->std_err[doy - 1][lyr - 1] = st_err; } - CloseFile(&f, LogInfo); + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -1494,8 +1602,8 @@ void _read_swc_hist( @param[out] LogInfo Holds information on warnings and errors */ void SW_SWC_adjust_swc( - RealD swcBulk[][MAX_LAYERS], - RealD swcBulk_min[], + double swcBulk[][MAX_LAYERS], + double swcBulk_min[], TimeInt doy, SW_SOILWAT_HIST SoilWat_hist, LyrIndex n_layers, @@ -1505,7 +1613,8 @@ void SW_SWC_adjust_swc( /* =================================================== */ /* 01/07/02 (cwb) added final loop to guarantee swc > swcBulk_min */ - RealD lower, upper; + double lower; + double upper; LyrIndex lyrIndex; TimeInt dy = doy - 1; @@ -1569,16 +1678,16 @@ Equations based on SWAT2K routines. @cite Neitsch2005 */ void SW_SWC_adjust_snow( - RealD *temp_snow, - RealD snowpack[], + double *temp_snow, + double snowpack[], SW_SITE *SW_Site, - RealD temp_min, - RealD temp_max, - RealD ppt, + double temp_min, + double temp_max, + double ppt, TimeInt doy, - RealD *rain, - RealD *snow, - RealD *snowmelt + double *rain, + double *snow, + double *snowmelt ) { /*************************************************************************** @@ -1595,9 +1704,12 @@ void SW_SWC_adjust_snow( ***********************************************************************/ - const RealD snow_cov = 1.; - RealD *snowpack_today = &snowpack[Today], temp_ave, Rmelt, SnowAccu = 0., - SnowMelt = 0.; + const double snow_cov = 1.; + double *snowpack_today = &snowpack[Today]; + double temp_ave; + double Rmelt; + double SnowAccu = 0.; + double SnowMelt = 0.; temp_ave = (temp_min + temp_max) / 2.; @@ -1652,9 +1764,9 @@ measured in cm. cm. */ -RealD SW_SWC_snowloss(RealD pet, RealD *snowpack) { - const RealD cov_soil = 0.5; - RealD snowloss; +double SW_SWC_snowloss(double pet, double *snowpack) { + const double cov_soil = 0.5; + double snowloss; if (GT(*snowpack, 0.)) { snowloss = fmax(0., fmin(*snowpack, cov_soil * pet)); @@ -1675,18 +1787,14 @@ RealD SW_SWC_snowloss(RealD pet, RealD *snowpack) { @return SW_SnowDepth Snow depth, measured in cm. */ -RealD SW_SnowDepth(RealD SWE, RealD snowdensity) { +double SW_SnowDepth(double SWE, double snowdensity) { /*--------------------- 08/22/2011 (drs) calculates depth of snowpack Input: SWE: snow water equivalents (cm = 10kg/m2) snowdensity (kg/m3) Output: snow depth (cm) ---------------------*/ - if (GT(snowdensity, 0.)) { - return SWE / snowdensity * 10. * 100.; - } else { - return 0.; - } + return (GT(snowdensity, 0.)) ? (SWE / snowdensity * 10. * 100.) : 0.; } /** @@ -1704,8 +1812,8 @@ See #swrc2str() for implemented SWRCs. @return Soil water potential [-bar] */ -RealD SW_SWRC_SWCtoSWP( - RealD swcBulk, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo +double SW_SWRC_SWCtoSWP( + double swcBulk, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo ) { return SWRC_SWCtoSWP( swcBulk, @@ -1855,7 +1963,9 @@ double SWRC_SWCtoSWP_Campbell1974( LOG_INFO *LogInfo ) { // assume that we have soil moisture - double theta, tmp, res; + double theta; + double tmp; + double res; // convert bulk SWC [cm] to theta = matric VWC [cm / cm] theta = swcBulk / (width * (1. - gravel)); @@ -1925,7 +2035,9 @@ double SWRC_SWCtoSWP_vanGenuchten1980( const int errmode, LOG_INFO *LogInfo ) { - double res, tmp, theta; + double res; + double tmp; + double theta; // convert bulk SWC [cm] to theta = matric VWC [cm / cm] theta = swcBulk / (width * (1. - gravel)); @@ -2013,7 +2125,8 @@ double SWRC_SWCtoSWP_FXW( const int errmode, LOG_INFO *LogInfo ) { - double res, theta; + double res; + double theta; // convert bulk SWC [cm] to theta = matric VWC [cm / cm] theta = swcBulk / (width * (1. - gravel)); @@ -2073,8 +2186,8 @@ See #swrc2str() for implemented SWRCs. @return Soil water content in the layer [cm] */ -RealD SW_SWRC_SWPtoSWC( - RealD swpMatric, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo +double SW_SWRC_SWPtoSWC( + double swpMatric, SW_SITE *SW_Site, LyrIndex layerno, LOG_INFO *LogInfo ) { return SWRC_SWPtoSWC( swpMatric, @@ -2189,7 +2302,8 @@ are the inverse of each other for `(phi, theta)` between double SWRC_SWPtoSWC_Campbell1974( double swpMatric, double *swrcp, double gravel, double width ) { - double phi, res; + double phi; + double res; // convert SWP [-bar] to phi [cm of H20; SOILWAT2 legacy value] phi = swpMatric * 1024.; @@ -2227,9 +2341,11 @@ are the inverse of each other for `(phi, theta)` between @return Soil water content in the layer [cm] */ double SWRC_SWPtoSWC_vanGenuchten1980( - double swpMatric, double *swrcp, double gravel, double width + double swpMatric, const double *swrcp, double gravel, double width ) { - double phi, tmp, res; + double phi; + double tmp; + double res; // convert SWP [-bar] to phi [cm of H2O at 4 C; // value from `soilDB::KSSL_VG_model()`] @@ -2266,7 +2382,8 @@ are the inverse of each other for `(phi, theta)` between double SWRC_SWPtoSWC_FXW( double swpMatric, double *swrcp, double gravel, double width ) { - double phi, res; + double phi; + double res; // convert SWP [-bar] to phi [cm of H2O at 4 C; // value from `soilDB::KSSL_VG_model()`] diff --git a/src/SW_VegEstab.c b/src/SW_VegEstab.c index af6923cbd..fb03288f2 100644 --- a/src/SW_VegEstab.c +++ b/src/SW_VegEstab.c @@ -24,10 +24,10 @@ 20090826 (drs) added return; after LBL_Normal_Exit: 06/26/2013 (rjm) closed open files in function SW_VES_read() or if - LogError() with LOGERROR is called in _read_spp() + LogError() with LOGERROR is called in read_spp() - 08/21/2013 (clk) changed the line v = SW_VegEstab.parms[ _new_species() - ]; -> v = SW_VegEstab.parms[ count ], where count = _new_species(); for some + 08/21/2013 (clk) changed the line v = SW_VegEstab.parms[ new_species() + ]; -> v = SW_VegEstab.parms[ count ], where count = new_species(); for some reason, without this change, a segmenation fault was occuring */ /********************************************************/ @@ -40,7 +40,7 @@ #include "include/SW_VegEstab.h" // for SW_ESTAB_BARS, SW_GERM_BARS, SW_... #include "include/filefuncs.h" // for LogError, CloseFile, GetALine -#include "include/generic.h" // for IntU, LOGERROR, RealD, isnull, LT +#include "include/generic.h" // for IntU, LOGERROR, isnull, LT #include "include/myMemory.h" // for Mem_Calloc, Mem_ReAlloc #include "include/SW_datastructs.h" // for SW_VEGESTAB_INFO, LOG_INFO, SW_V... #include "include/SW_Defines.h" // for TimeInt, eSW_Year, MAX_FILENAMESIZE @@ -50,35 +50,35 @@ #include "include/SW_VegProd.h" // for key2veg #include // for fabs #include // for NULL, snprintf, FILE, printf -#include // for atoi, atof, free -#include // for strcpy, strcat, strlen, memset +#include // for free +#include // for memccpy, strlen, memset /* =================================================== */ /* Private Function Declarations */ /* --------------------------------------------------- */ -static void _sanity_check( +static void sanity_check( unsigned int sppnum, - RealD swcBulk_wiltpt[], + double swcBulk_wiltpt[], LyrIndex n_transp_lyrs[], SW_VEGESTAB_INFO **parms, LOG_INFO *LogInfo ); -static void _read_spp( +static void read_spp( const char *infile, SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo ); -static void _checkit( +static void checkit( TimeInt doy, unsigned int sppnum, SW_WEATHER_NOW *wn, - RealD swcBulk[][MAX_LAYERS], + double swcBulk[][MAX_LAYERS], TimeInt firstdoy, SW_VEGESTAB_INFO **parms ); -static void _zero_state(unsigned int sppnum, SW_VEGESTAB_INFO **parms); +static void zero_state(unsigned int sppnum, SW_VEGESTAB_INFO **parms); /* =================================================== */ /* Global Function Definitions */ @@ -181,7 +181,7 @@ void SW_VES_deconstruct(SW_VEGESTAB *SW_VegEstab) { SW_VegEstab->parms[i] = NULL; } - free(SW_VegEstab->parms); + free((void *) SW_VegEstab->parms); SW_VegEstab->parms = NULL; } @@ -233,14 +233,17 @@ void SW_VES_new_year(IntU count) { @param[in,out] SW_VegEstab Struct of type SW_VEGESTAB holding all information about vegetation establishment within the simulation @param[in] InFiles Array of program in/output files -@param[in] _ProjDir Project directory +@param[in] SW_ProjDir Project directory @param[out] LogInfo Holds information on warnings and errors */ void SW_VES_read( - SW_VEGESTAB *SW_VegEstab, char *InFiles[], char *_ProjDir, LOG_INFO *LogInfo + SW_VEGESTAB *SW_VegEstab, + char *InFiles[], + char *SW_ProjDir, + LOG_INFO *LogInfo ) { - SW_VES_read2(SW_VegEstab, swTRUE, swTRUE, InFiles, _ProjDir, LogInfo); + SW_VES_read2(SW_VegEstab, swTRUE, swTRUE, InFiles, SW_ProjDir, LogInfo); } /** @@ -253,7 +256,7 @@ void SW_VES_read( @param[in] consider_InputFlag Should the user input flag read from `"estab.in"` be considered for turning on/off calculations of vegetation establishment. @param[in] InFiles Array of program in/output files -@param[in] _ProjDir Project directory +@param[in] SW_ProjDir Project directory @param[out] LogInfo Holds information on warnings and errors @note @@ -271,7 +274,7 @@ void SW_VES_read2( Bool use_VegEstab, Bool consider_InputFlag, char *InFiles[], - char *_ProjDir, + char *SW_ProjDir, LOG_INFO *LogInfo ) { @@ -284,7 +287,9 @@ void SW_VES_read2( SW_VegEstab->use = use_VegEstab; - char buf[FILENAME_MAX], inbuf[MAX_FILENAMESIZE]; + int resSNP; + char buf[FILENAME_MAX]; + char inbuf[MAX_FILENAMESIZE]; FILE *f; if (SW_VegEstab->use) { @@ -308,24 +313,31 @@ void SW_VES_read2( and read those files one by one */ while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { - // add `_ProjDir` to path, e.g., for STEPWAT2 - strcpy(buf, _ProjDir); - strcat(buf, inbuf); - _read_spp(buf, SW_VegEstab, LogInfo); + // add `SW_ProjDir` to path, e.g., for STEPWAT2 + resSNP = snprintf(buf, sizeof buf, "%s%s", SW_ProjDir, inbuf); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof buf)) { + LogError( + LogInfo, + LOGERROR, + "Establishment parameter file name is too long: '%s'.", + inbuf + ); + goto closeFile; + } + + read_spp(buf, SW_VegEstab, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } } SW_VegEstab_alloc_outptrs(SW_VegEstab, LogInfo); if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } } - CloseFile(&f, LogInfo); + closeFile: { CloseFile(&f, LogInfo); } } } @@ -404,7 +416,7 @@ void SW_VES_init_run( IntU i; for (i = 0; i < count; i++) { - _spp_init(parms, i, SW_Site, n_transp_lyrs, LogInfo); + spp_init(parms, i, SW_Site, n_transp_lyrs, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -427,16 +439,16 @@ void SW_VES_init_run( void SW_VES_checkestab( SW_VEGESTAB_INFO **parms, SW_WEATHER *SW_Weather, - RealD swcBulk[][MAX_LAYERS], + double swcBulk[][MAX_LAYERS], TimeInt doy, TimeInt firstdoy, IntU count ) { /* =================================================== */ - IntUS i; + IntU i; for (i = 0; i < count; i++) { - _checkit(doy, i, &SW_Weather->now, swcBulk, firstdoy, parms); + checkit(doy, i, &SW_Weather->now, swcBulk, firstdoy, parms); } } @@ -444,11 +456,11 @@ void SW_VES_checkestab( /* Local Function Definitions */ /* --------------------------------------------------- */ -static void _checkit( +static void checkit( TimeInt doy, unsigned int sppnum, SW_WEATHER_NOW *wn, - RealD swcBulk[][MAX_LAYERS], + double swcBulk[][MAX_LAYERS], TimeInt firstdoy, SW_VEGESTAB_INFO **parms ) { @@ -456,11 +468,11 @@ static void _checkit( SW_VEGESTAB_INFO *v = parms[sppnum]; IntU i; - RealF avgtemp = wn->temp_avg; /* avg of today's min/max temp */ - RealF avgswc; /* avg_swc today */ + double avgtemp = wn->temp_avg; /* avg of today's min/max temp */ + double avgswc; /* avg_swc today */ if (doy == firstdoy) { - _zero_state(sppnum, parms); + zero_state(sppnum, parms); } if (v->no_estab || v->estab_doy > 0) { @@ -501,10 +513,11 @@ static void _checkit( /* any dry period (> max_drydays) or temp out of range * after germination means restart */ - for (i = avgswc = 0; i < v->estab_lyrs;) { + avgswc = 0.; + for (i = 0; i < v->estab_lyrs;) { avgswc += swcBulk[Today][i++]; } - avgswc /= (RealF) v->estab_lyrs; + avgswc /= (double) v->estab_lyrs; if (LT(avgswc, v->min_swc_estab)) { v->drydays_postgerm++; v->wetdays_for_estab = 0; @@ -545,7 +558,7 @@ static void _checkit( return; } -static void _zero_state(unsigned int sppnum, SW_VEGESTAB_INFO **parms) { +static void zero_state(unsigned int sppnum, SW_VEGESTAB_INFO **parms) { /* =================================================== */ /* zero any values that need it for the new growing season */ @@ -557,27 +570,42 @@ static void _zero_state(unsigned int sppnum, SW_VEGESTAB_INFO **parms) { parms_sppnum->wetdays_for_germ = parms_sppnum->wetdays_for_estab = 0; } -static void _read_spp( +static void read_spp( const char *infile, SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo ) { /* =================================================== */ + SW_VEGESTAB_INFO *v; const int nitems = 16; FILE *f; int lineno = 0; + int resSNP; char name[80]; /* only allow 4 char sppnames */ char inbuf[MAX_FILENAMESIZE]; + int inBufintRes = 0; + double inBufDoubleVal = 0.; + + Bool doIntConv; IntU count; - count = _new_species(SW_VegEstab, LogInfo); + count = new_species(SW_VegEstab, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } v = SW_VegEstab->parms[count]; // have to copy before the pointer infile gets reset below by getAline - strcpy(v->sppFileName, infile); + resSNP = snprintf(v->sppFileName, sizeof v->sppFileName, "%s", infile); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof v->sppFileName)) { + LogError( + LogInfo, + LOGERROR, + "Establishment parameter file name is too long: '%s'.", + infile + ); + return; // Exit function prematurely due to error + } f = OpenFile(infile, "r", LogInfo); if (LogInfo->stopRun) { @@ -585,60 +613,96 @@ static void _read_spp( } while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { + + if (lineno >= 1 && lineno <= 15) { + /* Check to see if the line number contains an integer or double + * value */ + doIntConv = (Bool) ((lineno >= 1 && lineno <= 2) || + (lineno >= 5 && lineno <= 11)); + + if (doIntConv) { + inBufintRes = sw_strtoi(inbuf, infile, LogInfo); + } else { + inBufDoubleVal = sw_strtod(inbuf, infile, LogInfo); + } + + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (lineno) { case 0: - strcpy(name, inbuf); + resSNP = snprintf(name, sizeof name, "%s", inbuf); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof name)) { + LogError( + LogInfo, + LOGERROR, + "Establishment species name is too long: '%s'.", + inbuf + ); + goto closeFile; + } break; case 1: - v->vegType = atoi(inbuf); + v->vegType = inBufintRes; break; case 2: - v->estab_lyrs = atoi(inbuf); + v->estab_lyrs = inBufintRes; break; case 3: - v->bars[SW_GERM_BARS] = fabs(atof(inbuf)); + v->bars[SW_GERM_BARS] = fabs(inBufDoubleVal); break; case 4: - v->bars[SW_ESTAB_BARS] = fabs(atof(inbuf)); + v->bars[SW_ESTAB_BARS] = fabs(inBufDoubleVal); break; case 5: - v->min_pregerm_days = atoi(inbuf); + v->min_pregerm_days = inBufintRes; break; case 6: - v->max_pregerm_days = atoi(inbuf); + v->max_pregerm_days = inBufintRes; break; case 7: - v->min_wetdays_for_germ = atoi(inbuf); + v->min_wetdays_for_germ = inBufintRes; break; case 8: - v->max_drydays_postgerm = atoi(inbuf); + v->max_drydays_postgerm = inBufintRes; break; case 9: - v->min_wetdays_for_estab = atoi(inbuf); + v->min_wetdays_for_estab = inBufintRes; break; case 10: - v->min_days_germ2estab = atoi(inbuf); + v->min_days_germ2estab = inBufintRes; break; case 11: - v->max_days_germ2estab = atoi(inbuf); + v->max_days_germ2estab = inBufintRes; break; case 12: - v->min_temp_germ = atof(inbuf); + v->min_temp_germ = inBufDoubleVal; break; case 13: - v->max_temp_germ = atof(inbuf); + v->max_temp_germ = inBufDoubleVal; break; case 14: - v->min_temp_estab = atof(inbuf); + v->min_temp_estab = inBufDoubleVal; break; case 15: - v->max_temp_estab = atof(inbuf); + v->max_temp_estab = inBufDoubleVal; + break; + default: + LogError( + LogInfo, + LOGERROR, + "read_spp(): incorrect format of input file '%s'.", + infile + ); + goto closeFile; break; } + /* check for valid name first */ if (0 == lineno) { if (strlen(name) > MAX_SPECIESNAMELEN) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -648,23 +712,22 @@ static void _read_spp( name, MAX_SPECIESNAMELEN ); - return; // Exit function prematurely due to error - } else { - strcpy(v->sppname, name); + goto closeFile; } + + (void) sw_memccpy(v->sppname, name, '\0', sizeof(v->sppname)); } lineno++; /*only increments when there's a value */ } - CloseFile(&f, LogInfo); - if (lineno != nitems) { LogError( LogInfo, LOGERROR, "%s : Too few/many input parameters.\n", infile ); - return; // Exit function prematurely due to error } + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -678,7 +741,7 @@ other function call. @param[in] n_transp_lyrs Layer index of deepest transp. region. @param[out] LogInfo Holds information on warnings and errors */ -void _spp_init( +void spp_init( SW_VEGESTAB_INFO **parms, unsigned int sppnum, SW_SITE *SW_Site, @@ -710,16 +773,16 @@ void _spp_init( return; // Exit function prematurely due to error } } - parms_sppnum->min_swc_estab /= parms_sppnum->estab_lyrs; + parms_sppnum->min_swc_estab /= (double) parms_sppnum->estab_lyrs; - _sanity_check( + sanity_check( sppnum, SW_Site->swcBulk_wiltpt, n_transp_lyrs, parms, LogInfo ); } -static void _sanity_check( +static void sanity_check( unsigned int sppnum, - RealD swcBulk_wiltpt[], + double swcBulk_wiltpt[], LyrIndex n_transp_lyrs[], SW_VEGESTAB_INFO **parms, LOG_INFO *LogInfo @@ -799,7 +862,7 @@ static void _sanity_check( for (i = 0; i < parms_sppnum->estab_lyrs; i++) { mean_wiltpt += swcBulk_wiltpt[i]; } - mean_wiltpt /= parms_sppnum->estab_lyrs; + mean_wiltpt /= (double) parms_sppnum->estab_lyrs; if (LT(parms_sppnum->min_swc_estab, mean_wiltpt)) { LogError( @@ -827,7 +890,7 @@ required. For each species thereafter realloc() is called. @return (++SW_VegEstab->count) - 1 */ -IntU _new_species(SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo) { +IntU new_species(SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo) { const char *me = "SW_VegEstab_newspecies()"; @@ -837,7 +900,7 @@ IntU _new_species(SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo) { SW_VegEstab->count + 1, sizeof(SW_VEGESTAB_INFO *), me, LogInfo ) : (SW_VEGESTAB_INFO **) Mem_ReAlloc( - SW_VegEstab->parms, + (void *) SW_VegEstab->parms, sizeof(SW_VEGESTAB_INFO *) * (SW_VegEstab->count + 1), LogInfo ); @@ -861,12 +924,20 @@ IntU _new_species(SW_VEGESTAB *SW_VegEstab, LOG_INFO *LogInfo) { @param[in] count Held within type SW_VEGESTAB to determine how many species to check */ -void _echo_VegEstab(RealD width[], SW_VEGESTAB_INFO **parms, IntU count) { +void echo_VegEstab(const double width[], SW_VEGESTAB_INFO **parms, IntU count) { /* --------------------------------------------------- */ IntU i; - char outstr[2048], errstr[MAX_ERROR]; + char outstr[MAX_ERROR]; + char errstr[MAX_ERROR]; - snprintf( + const char *endDispStr = + "\n----------------- End of Establishment Parameters ------------\n"; + + size_t writeSize = MAX_ERROR; + char *writePtr = outstr; + char *resPtr = NULL; + + (void) snprintf( errstr, MAX_ERROR, "\n=========================================================\n\n" @@ -876,9 +947,10 @@ void _echo_VegEstab(RealD width[], SW_VEGESTAB_INFO **parms, IntU count) { count ); - strcpy(outstr, errstr); + (void) sw_memccpy(outstr, errstr, '\0', sizeof outstr); + for (i = 0; i < count; i++) { - snprintf( + (void) snprintf( errstr, MAX_ERROR, "Species: %s (vegetation type %s [%d])\n----------------\n" @@ -904,7 +976,7 @@ void _echo_VegEstab(RealD width[], SW_VEGESTAB_INFO **parms, IntU count) { parms[i]->min_wetdays_for_germ ); - snprintf( + (void) snprintf( errstr, MAX_ERROR, "Establishment parameters:\n" @@ -931,12 +1003,13 @@ void _echo_VegEstab(RealD width[], SW_VEGESTAB_INFO **parms, IntU count) { parms[i]->max_drydays_postgerm ); - strcat(outstr, errstr); + resPtr = (char *) sw_memccpy( + (void *) writePtr, (void *) errstr, '\0', writeSize + ); + writePtr = resPtr - 1; + writeSize -= (resPtr - outstr - 1); } - strcat( - outstr, - "\n----------------- End of Establishment Parameters ------------\n" - ); + sw_memccpy(outstr, (char *) endDispStr, '\0', writeSize); printf("%s\n", outstr); } diff --git a/src/SW_VegProd.c b/src/SW_VegProd.c index 882cc6798..69194ab45 100644 --- a/src/SW_VegProd.c +++ b/src/SW_VegProd.c @@ -92,7 +92,7 @@ vegtype variable forb and forb.cov.fCover /* --------------------------------------------------- */ #include "include/SW_VegProd.h" // for BIO_INDEX, SW_VPD_alloc_outptrs #include "include/filefuncs.h" // for LogError, CloseFile, GetALine -#include "include/generic.h" // for LOGERROR, Bool, LOGWARN, RealF, GT +#include "include/generic.h" // for LOGERROR, Bool, LOGWARN, GT #include "include/myMemory.h" // for Mem_Calloc, Mem_Malloc #include "include/SW_datastructs.h" // for SW_VEGPROD, LOG_INFO, SW_VEGPROD... #include "include/SW_Defines.h" // for ForEachVegType, NVEGTYPES, SW_TREES @@ -111,7 +111,7 @@ vegtype variable forb and forb.cov.fCover // key2veg must be in the same order as the indices to vegetation types defined // in SW_Defines.h -char const *key2veg[NVEGTYPES] = {"Trees", "Shrubs", "Forbs", "Grasses"}; +const char *const key2veg[NVEGTYPES] = {"Trees", "Shrubs", "Forbs", "Grasses"}; /* =================================================== */ /* Global Function Definitions */ @@ -127,13 +127,62 @@ char const *key2veg[NVEGTYPES] = {"Trees", "Shrubs", "Forbs", "Grasses"}; */ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* =================================================== */ + + const char *const lineErrStrings[] = { + "vegetation type components", + "vegetation type components", + "albedo values", + "canopy xinflec", + "canopy yinflec", + "canopy range", + "canopy slope", + "canopy height constant option", + "interception parameter kSmax(veg)", + "interception parameter kdead(veg)", + "litter interception parameter kSmax(litter)", + "parameter for partitioning of bare-soil evaporation and transpiration", + "parameter for Parameter for scaling and limiting bare soil ", + "evaporation rate", + "shade scale", + "shade max dead biomass", + "shade xinflec", + "shade yinflec", + "shade range", + "shade slope", + "hydraulic redistribution: flag", + "hydraulic redistribution: maxCondroot", + "hydraulic redistribution: swpMatric50", + "hydraulic redistribution: shapeCond", + "critical soil water potentials: flag", + "CO2 Biomass Coefficient 1", + "CO2 Biomass Coefficient 2", + "CO2 WUE Coefficient 1", + "CO2 WUE Coefficient 2" + }; + FILE *f; TimeInt mon = Jan; - int x, k, lineno = 0, veg_method; + int x; + int k; + int lineno = 0; + int index; // last case line number before monthly biomass densities const int line_help = 28; - RealF help_veg[NVEGTYPES], help_bareGround, litt, biom, pctl, laic; - char *MyFileName, inbuf[MAX_FILENAMESIZE]; + double help_veg[NVEGTYPES]; + double help_bareGround = 0.; + double litt; + double biom; + double pctl; + double laic; + double *monBioVals[] = {&litt, &biom, &pctl, &laic}; + char *MyFileName; + char inbuf[MAX_FILENAMESIZE]; + char vegStrs[NVEGTYPES][20] = {{'\0'}}; + char bareGroundStr[20] = {'\0'}; + char *startOfErrMsg; + char vegMethodStr[20] = {'\0'}; + const int numMonthVals = 4; + int expectedNumInVals; MyFileName = InFiles[eVegProd]; f = OpenFile(MyFileName, "r", LogInfo); @@ -142,46 +191,75 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { } while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { - if (lineno++ < line_help) { + lineno++; + + if (lineno >= 2 && lineno <= 28) { + x = sscanf( + inbuf, + "%19s %19s %19s %19s %19s", + vegStrs[SW_GRASS], + vegStrs[SW_SHRUB], + vegStrs[SW_TREES], + vegStrs[SW_FORBS], + bareGroundStr + ); + + startOfErrMsg = (lineno >= 25) ? (char *) "Not enough arguments" : + (char *) "Invalid record in"; + + expectedNumInVals = (lineno >= 4) ? NVEGTYPES : NVEGTYPES + 1; + + if (x < expectedNumInVals) { + LogError( + LogInfo, + LOGERROR, + "%s %s in %s\n", + startOfErrMsg, + lineErrStrings[lineno - 1], + MyFileName + ); + goto closeFile; + } + + ForEachVegType(k) { + help_veg[k] = sw_strtof(vegStrs[k], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + + if (x == NVEGTYPES + 1) { + help_bareGround = sw_strtof(bareGroundStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + } + + if (lineno - 1 < line_help) { /* Compare to `line_help` in base0 */ switch (lineno) { case 1: - x = sscanf(inbuf, "%d", &veg_method); + x = sscanf(inbuf, "%19s", vegMethodStr); if (x != 1) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, - "ERROR: invalid record" - " in vegetation type components in %s\n", + "invalid record in %s in %s\n", + lineErrStrings[0], MyFileName ); - return; // Exit function prematurely due to error + goto closeFile; + } + + SW_VegProd->veg_method = + sw_strtoi(vegMethodStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; } - SW_VegProd->veg_method = veg_method; break; /* fractions of vegetation types */ case 2: - x = sscanf( - inbuf, - "%f %f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS], - &help_bareGround - ); - if (x < NVEGTYPES + 1) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " vegetation type components in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].cov.fCover = help_veg[k]; } @@ -190,26 +268,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* albedo */ case 3: - x = sscanf( - inbuf, - "%f %f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS], - &help_bareGround - ); - if (x < NVEGTYPES + 1) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " albedo values in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].cov.albedo = help_veg[k]; } @@ -218,125 +276,30 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* canopy height */ case 4: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " canopy xinflec in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].cnpy.xinflec = help_veg[k]; } break; case 5: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " canopy yinflec in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].cnpy.yinflec = help_veg[k]; } break; case 6: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " canopy range in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].cnpy.range = help_veg[k]; } break; case 7: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " canopy slope in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].cnpy.slope = help_veg[k]; } break; case 8: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " canopy height constant option in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].canopy_height_constant = help_veg[k]; } @@ -344,50 +307,12 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* vegetation interception parameters */ case 9: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " interception parameter kSmax(veg) in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].veg_kSmax = help_veg[k]; } break; case 10: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " interception parameter kdead(veg) in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].veg_kdead = help_veg[k]; } @@ -395,26 +320,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* litter interception parameters */ case 11: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " litter interception parameter kSmax(litter)" - " in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].lit_kSmax = help_veg[k]; } @@ -423,26 +328,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* parameter for partitioning of bare-soil evaporation and * transpiration */ case 12: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " parameter for partitioning of bare-soil" - " evaporation and transpiration in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].EsTpartitioning_param = help_veg[k]; } @@ -450,26 +335,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* Parameter for scaling and limiting bare soil evaporation rate */ case 13: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " parameter for Parameter for scaling and" - " limiting bare soil evaporation rate in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].Es_param_limit = help_veg[k]; } @@ -477,150 +342,36 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* shade effects */ case 14: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " shade scale in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].shade_scale = help_veg[k]; } break; case 15: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " shade max dead biomass in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].shade_deadmax = help_veg[k]; } break; case 16: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " shade xinflec in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].tr_shade_effects.xinflec = help_veg[k]; } break; case 17: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " shade yinflec in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].tr_shade_effects.yinflec = help_veg[k]; } break; case 18: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " shade range in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].tr_shade_effects.range = help_veg[k]; } break; case 19: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " shade slope in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].tr_shade_effects.slope = help_veg[k]; } @@ -628,25 +379,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* Hydraulic redistribution */ case 20: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " hydraulic redistribution: flag in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].flagHydraulicRedistribution = (Bool) EQ(help_veg[k], 1.); @@ -654,75 +386,18 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { break; case 21: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " hydraulic redistribution: maxCondroot in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].maxCondroot = help_veg[k]; } break; case 22: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " hydraulic redistribution: swpMatric50 in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].swpMatric50 = help_veg[k]; } break; case 23: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " hydraulic redistribution: shapeCond in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].shapeCond = help_veg[k]; } @@ -730,25 +405,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* Critical soil water potential */ case 24: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: invalid record in" - " critical soil water potentials: flag in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].SWPcrit = -10. * help_veg[k]; SW_VegProd->critSoilWater[k] = @@ -761,25 +417,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* CO2 Biomass Power Equation */ // Coefficient 1 case 25: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: Not enough arguments" - " for CO2 Biomass Coefficient 1 in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].co2_bio_coeff1 = help_veg[k]; } @@ -787,25 +424,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { // Coefficient 2 case 26: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: Not enough arguments" - " for CO2 Biomass Coefficient 2 in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].co2_bio_coeff2 = help_veg[k]; } @@ -814,25 +432,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { /* CO2 WUE Power Equation */ // Coefficient 1 case 27: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: Not enough arguments" - " for CO2 WUE Coefficient 1 in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].co2_wue_coeff1 = help_veg[k]; } @@ -840,25 +439,6 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { // Coefficient 2 case 28: - x = sscanf( - inbuf, - "%f %f %f %f", - &help_veg[SW_GRASS], - &help_veg[SW_SHRUB], - &help_veg[SW_TREES], - &help_veg[SW_FORBS] - ); - if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); - LogError( - LogInfo, - LOGERROR, - "ERROR: Not enough arguments" - " for CO2 WUE Coefficient 2 in %s\n", - MyFileName - ); - return; // Exit function prematurely due to error - } ForEachVegType(k) { SW_VegProd->veg[k].co2_wue_coeff2 = help_veg[k]; } @@ -875,9 +455,16 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { mon = Jan; } - x = sscanf(inbuf, "%f %f %f %f", &litt, &biom, &pctl, &laic); + x = sscanf( + inbuf, + "%19s %19s %19s %19s", + vegStrs[0], + vegStrs[1], + vegStrs[2], + vegStrs[3] + ); + if (x < NVEGTYPES) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -885,8 +472,17 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { mon + 1, MyFileName ); - return; // Exit function prematurely due to error + goto closeFile; } + + for (index = 0; index < numMonthVals; index++) { + *(monBioVals[index]) = + sw_strtof(vegStrs[index], MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + } + if (lineno > line_help + 12 * 3 && lineno <= line_help + 12 * 4) { SW_VegProd->veg[SW_FORBS].litter[mon] = litt; SW_VegProd->veg[SW_FORBS].biomass[mon] = biom; @@ -927,7 +523,7 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { SW_VPD_fix_cover(SW_VegProd, LogInfo); - CloseFile(&f, LogInfo); +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -944,7 +540,7 @@ void SW_VPD_read(SW_VEGPROD *SW_VegProd, char *InFiles[], LOG_INFO *LogInfo) { */ void SW_VPD_fix_cover(SW_VEGPROD *SW_VegProd, LOG_INFO *LogInfo) { int k; - RealD fraction_sum = 0.; + double fraction_sum = 0.; fraction_sum = SW_VegProd->bare_cov.fCover; ForEachVegType(k) { fraction_sum += SW_VegProd->veg[k].cov.fCover; } @@ -1104,7 +700,7 @@ on the biomass. @sideeffect new_biomass Updated biomass. */ void apply_biomassCO2effect( - double new_biomass[], double biomass[], double multiplier + double new_biomass[], const double biomass[], double multiplier ) { int i; for (i = 0; i < 12; i++) { @@ -1297,9 +893,9 @@ void SW_VPD_new_year(SW_VEGPROD *SW_VegProd, SW_MODEL *SW_Model) { @param[in] layerno Current layer which is being worked with @return Sum across `*x` */ -RealD sum_across_vegtypes(RealD x[][MAX_LAYERS], LyrIndex layerno) { +double sum_across_vegtypes(double x[][MAX_LAYERS], LyrIndex layerno) { unsigned int k; - RealD sum = 0.; + double sum = 0.; ForEachVegType(k) { sum += x[k][layerno]; } @@ -1314,7 +910,7 @@ RealD sum_across_vegtypes(RealD x[][MAX_LAYERS], LyrIndex layerno) { @param[in] VegProd_bare_cov Bare-ground cover of plot that is not occupied by vegetation */ -void _echo_VegProd(VegType VegProd_veg[], CoverType VegProd_bare_cov) { +void echo_VegProd(VegType VegProd_veg[], CoverType VegProd_bare_cov) { /* ================================================== */ int k; @@ -1355,12 +951,15 @@ void get_critical_rank(SW_VEGPROD *SW_VegProd) { /*---------------------------------------------------------- Get proper order for rank_SWPcrits ----------------------------------------------------------*/ - int i, outerLoop, innerLoop; - float key; + int i; + int outerLoop; + int innerLoop; + double key; // need two temp arrays equal to critSoilWater since we dont want to alter // the original at all - RealF tempArray[NVEGTYPES], tempArrayUnsorted[NVEGTYPES]; + double tempArray[NVEGTYPES]; + double tempArrayUnsorted[NVEGTYPES]; ForEachVegType(i) { tempArray[i] = SW_VegProd->critSoilWater[i]; @@ -1422,29 +1021,35 @@ void estimateVegetationFromClimate( LOG_INFO *LogInfo ) { - int numYears = SW_Model->endyr - SW_Model->startyr + 1, k, - bareGroundIndex = 7; + unsigned int numYears = SW_Model->endyr - SW_Model->startyr + 1; + unsigned int k; + unsigned int bareGroundIndex = 7; SW_CLIMATE_YEARLY climateOutput; SW_CLIMATE_CLIM climateAverages; // NOTE: 8 = number of types, 5 = (number of types) - grasses - double coverValues[8] = - {SW_MISSING, - SW_MISSING, - SW_MISSING, - SW_MISSING, - 0.0, - SW_MISSING, - 0.0, - 0.0}, - shrubLimit = .2; - - double SumGrassesFraction = SW_MISSING, C4Variables[3], grassOutput[3], - RelAbundanceL0[8], RelAbundanceL1[5]; - - Bool fillEmptyWithBareGround = swTRUE, warnExtrapolation = swTRUE; + double coverValues[8] = { + SW_MISSING, + SW_MISSING, + SW_MISSING, + SW_MISSING, + 0.0, + SW_MISSING, + 0.0, + 0.0 + }; + double shrubLimit = .2; + + double SumGrassesFraction = SW_MISSING; + double C4Variables[3]; + double grassOutput[3]; + double RelAbundanceL0[8]; + double RelAbundanceL1[5]; + + Bool fillEmptyWithBareGround = swTRUE; + Bool warnExtrapolation = swTRUE; Bool inNorthHem = swTRUE; Bool fixBareGround = swTRUE; @@ -1620,7 +1225,7 @@ void estimatePotNatVegComposition( double meanTemp_C, double PPT_cm, double meanTempMon_C[], - double PPTMon_cm[], + const double PPTMon_cm[], double inputValues[], double shrubLimit, double SumGrassesFraction, @@ -1636,28 +1241,54 @@ void estimatePotNatVegComposition( ) { const int nTypes = 8; - int winterMonths[3], summerMonths[3]; + int winterMonths[3]; + int summerMonths[3]; // Indices both single value and arrays - int index, succIndex = 0, forbIndex = 1, C3Index = 2, C4Index = 3, - grassAnn = 4, shrubIndex = 5, treeIndex = 6, bareGround = 7, - grassEstimSize = 0, overallEstimSize = 0, julyMin = 0, - degreeAbove65 = 1, frostFreeDays = 2, estimIndicesNotNA = 0, - grassesEstim[3], overallEstim[nTypes], iFixed[nTypes], - iFixedSize = 0; + int index; + int succIndex = 0; + int forbIndex = 1; + int C3Index = 2; + int C4Index = 3; + int grassAnn = 4; + int shrubIndex = 5; + int treeIndex = 6; + int bareGround = 7; + int grassEstimSize = 0; + int overallEstimSize = 0; + int julyMin = 0; + int degreeAbove65 = 1; + int frostFreeDays = 2; + int estimIndicesNotNA = 0; + int grassesEstim[3]; + int overallEstim[nTypes]; + int iFixed[nTypes]; + int iFixedSize = 0; + int tempSwapValue; int isetIndices[3] = {grassAnn, treeIndex, bareGround}; const char *txt_isetIndices[] = {"annual grasses", "trees", "bare ground"}; // Totals of different areas of variables - double totalSumGrasses = 0., inputSumGrasses = 0., tempDiffJanJul, - summerMAP = 0., winterMAP = 0., C4Species = SW_MISSING, C3Grassland, - C3Shrubland, estimGrassSum = 0, finalVegSum = 0., estimCoverSum = 0., - tempSumGrasses = 0., estimCover[nTypes], initialVegSum = 0., - tempSwapValue, fixedValuesSum = 0; + double totalSumGrasses = 0.; + double inputSumGrasses = 0.; + double tempDiffJanJul; + double summerMAP = 0.; + double winterMAP = 0.; + double C4Species = SW_MISSING; + double C3Grassland; + double C3Shrubland; + double estimGrassSum = 0; + double finalVegSum = 0.; + double estimCoverSum = 0.; + double tempSumGrasses = 0.; + double estimCover[nTypes]; + double initialVegSum = 0.; + double fixedValuesSum = 0; Bool fixSumGrasses = (Bool) (!missing(SumGrassesFraction)); - Bool isGrassIndex = swFALSE, tempShrubBool; + Bool isGrassIndex = swFALSE; + Bool tempShrubBool; // Land cover/vegetation types that are not estimated @@ -2140,11 +1771,7 @@ value to go below zero @return A value that is either above or equal to zero */ double cutZeroInf(double testValue) { - if (LT(testValue, 0.)) { - return 0.; - } else { - return testValue; - } + return (LT(testValue, 0.)) ? 0. : testValue; } /** @@ -2162,8 +1789,8 @@ indices from two input arrays @param[out] LogInfo Holds information on warnings and errors */ void uniqueIndices( - int arrayOne[], - int arrayTwo[], + const int arrayOne[], + const int arrayTwo[], int arrayOneSize, int arrayTwoSize, int *finalIndexArray, @@ -2171,10 +1798,13 @@ void uniqueIndices( LOG_INFO *LogInfo ) { - int index, finalArrayIndex = 0, nTypes = 8, - tempSize = arrayOneSize + arrayTwoSize + finalArrayIndex, - tempIndex = 0; - int *tempArray, *tempArraySeen; + int index; + int finalArrayIndex = 0; + int nTypes = 8; + int tempSize = arrayOneSize + arrayTwoSize + finalArrayIndex; + int tempIndex = 0; + int *tempArray; + int *tempArraySeen; tempArray = (int *) Mem_Malloc(sizeof(int) * tempSize, "uniqueIndices()", LogInfo); diff --git a/src/SW_Weather.c b/src/SW_Weather.c index d912ebb3d..bfbe72ba7 100644 --- a/src/SW_Weather.c +++ b/src/SW_Weather.c @@ -57,7 +57,7 @@ 06/21/2013 (DLM) variable 'tail' got too large by 1 and leaked memory when accessing array runavg_list[] in function _runavg_temp(): changed test from '(tail < SW_Weather.days_in_runavg)' to '(tail < - (SW_Weather.days_in_runavg-1))' in function _clear_hist_weather() temp_max was + (SW_Weather.days_in_runavg-1))' in function clear_hist_weather() temp_max was tested twice, one should be temp_min 06/24/2013 (rjm) added function void SW_WTH_clear_runavg_list(void) to free @@ -93,8 +93,8 @@ #include "include/Times.h" // for Time_get_lastdoy_y, Time_days_i... #include // for exp, fmin, fmax #include // for NULL, sscanf, FILE, fclose, fopen -#include // for atoi, free -#include // for memset, NULL, strcpy +#include // for free +#include // for memset, NULL /* =================================================== */ /* Local Function Definitions */ @@ -113,11 +113,11 @@ averages and standard deviations output by `averageClimateAcrossYears()` */ void averageClimateAcrossYears( SW_CLIMATE_YEARLY *climateOutput, - int numYears, + unsigned int numYears, SW_CLIMATE_CLIM *climateAverages ) { - int month; + unsigned int month; // Take long-term average of monthly mean, maximum and minimum temperature // and precipitation throughout "numYears" @@ -210,32 +210,47 @@ void calcSiteClimate( SW_WEATHER_HIST **allHist, TimeInt cum_monthdays[], TimeInt days_in_month[], - int numYears, - int startYear, + unsigned int numYears, + unsigned int startYear, Bool inNorthHem, SW_CLIMATE_YEARLY *climateOutput ) { - int month, yearIndex, year, day, numDaysYear, currMonDay; - int numDaysMonth, adjustedDoy, adjustedYear = 0, secondMonth, seventhMonth; - int adjustedStartYear, calendarYearDays; - - double currentTempMin, currentTempMean, totalAbove65, current7thMonMin, - PPT7thMon, consecNonFrost, currentNonFrost; + unsigned int month; + unsigned int yearIndex; + unsigned int year; + unsigned int day; + unsigned int numDaysYear; + unsigned int currMonDay; + unsigned int numDaysMonth; + unsigned int adjustedDoy; + unsigned int adjustedYear = 0; + unsigned int secondMonth; + unsigned int seventhMonth; + unsigned int adjustedStartYear; + unsigned int calendarYearDays; + + double currentTempMin; + double currentTempMean; + double totalAbove65; + double current7thMonMin; + double PPT7thMon; + double consecNonFrost; + double currentNonFrost; size_t size_nyrs = sizeof(double) * numYears; // Initialize accumulated value arrays to all zeros for (month = 0; month < MAX_MONTHS; month++) { - memset(climateOutput->meanTempMon_C[month], 0., size_nyrs); - memset(climateOutput->maxTempMon_C[month], 0., size_nyrs); - memset(climateOutput->minTempMon_C[month], 0., size_nyrs); - memset(climateOutput->PPTMon_cm[month], 0., size_nyrs); + memset(climateOutput->meanTempMon_C[month], 0, size_nyrs); + memset(climateOutput->maxTempMon_C[month], 0, size_nyrs); + memset(climateOutput->minTempMon_C[month], 0, size_nyrs); + memset(climateOutput->PPTMon_cm[month], 0, size_nyrs); } - memset(climateOutput->PPT_cm, 0., size_nyrs); - memset(climateOutput->meanTemp_C, 0., size_nyrs); - memset(climateOutput->minTemp2ndMon_C, 0., size_nyrs); - memset(climateOutput->minTemp7thMon_C, 0., size_nyrs); + memset(climateOutput->PPT_cm, 0, size_nyrs); + memset(climateOutput->meanTemp_C, 0, size_nyrs); + memset(climateOutput->minTemp2ndMon_C, 0, size_nyrs); + memset(climateOutput->minTemp7thMon_C, 0, size_nyrs); calcSiteClimateLatInvariants( allHist, @@ -307,7 +322,6 @@ void calcSiteClimate( totalAbove65 = SW_MISSING; currentNonFrost = SW_MISSING; consecNonFrost = SW_MISSING; - currMonDay = SW_MISSING; break; } @@ -366,6 +380,7 @@ void calcSiteClimate( totalAbove65 += (currentTempMean > 0.0) ? currentTempMean : 0.0; } } + // Set all values climateOutput->minTemp7thMon_C[yearIndex] = current7thMonMin; climateOutput->PPT7thMon_mm[yearIndex] = PPT7thMon; @@ -403,13 +418,18 @@ void calcSiteClimateLatInvariants( SW_WEATHER_HIST **allHist, TimeInt cum_monthdays[], TimeInt days_in_month[], - int numYears, - int startYear, + unsigned int numYears, + unsigned int startYear, SW_CLIMATE_YEARLY *climateOutput ) { - int month = Jan, numDaysMonth = Time_days_in_month(month, days_in_month), - yearIndex, day, numDaysYear, currMonDay, year; + unsigned int month = Jan; + unsigned int numDaysMonth = Time_days_in_month(month, days_in_month); + unsigned int yearIndex; + unsigned int day; + unsigned int numDaysYear; + unsigned int currMonDay; + unsigned int year; for (yearIndex = 0; yearIndex < numYears; yearIndex++) { year = yearIndex + startYear; @@ -462,24 +482,33 @@ during the driest quarter of the year numYears */ void findDriestQtr( - int numYears, + unsigned int numYears, Bool inNorthHem, double *meanTempDriestQtr_C, double **meanTempMon_C, double **PPTMon_cm ) { - int yearIndex, month, prevMonth, nextMonth, - adjustedMonth = 0, numQuarterMonths = 3, - endNumYears = (inNorthHem) ? numYears : numYears - 1; + unsigned int yearIndex; + unsigned int month; + unsigned int prevMonth; + unsigned int nextMonth; + unsigned int adjustedMonth = 0; + unsigned int numQuarterMonths = 3; + unsigned int endNumYears = (inNorthHem) ? numYears : numYears - 1; // NOTE: These variables are the same throughout the program if site is in // northern hempisphere // The main purpose of these are to easily control the correct year when // dealing with adjusted years in the southern hempisphere - int adjustedYearZero = 0, adjustedYearOne = 0, adjustedYearTwo = 0; + unsigned int adjustedYearZero = 0; + unsigned int adjustedYearOne = 0; + unsigned int adjustedYearTwo = 0; - double driestThreeMonPPT, driestMeanTemp, currentQtrPPT, currentQtrTemp; + double driestThreeMonPPT; + double driestMeanTemp; + double currentQtrPPT; + double currentQtrTemp; for (yearIndex = 0; yearIndex < endNumYears; yearIndex++) { driestThreeMonPPT = SW_MISSING; @@ -555,13 +584,13 @@ years. @param[in,out] nextMonth Month following current input month */ void driestQtrSouthAdjMonYears( - int month, - int *adjustedYearZero, - int *adjustedYearOne, - int *adjustedYearTwo, - int *adjustedMonth, - int *prevMonth, - int *nextMonth + unsigned int month, + unsigned int *adjustedYearZero, + unsigned int *adjustedYearOne, + unsigned int *adjustedYearTwo, + unsigned int *adjustedMonth, + unsigned int *prevMonth, + unsigned int *nextMonth ) { *adjustedMonth = month + Jul; *adjustedMonth %= MAX_MONTHS; @@ -649,7 +678,7 @@ series */ void readAllWeather( SW_WEATHER_HIST **allHist, - int startYear, + unsigned int startYear, unsigned int n_years, Bool use_weathergenerator_only, char weather_prefix[], @@ -659,14 +688,15 @@ void readAllWeather( unsigned int n_input_forcings, unsigned int *dailyInputIndices, Bool *dailyInputFlags, - RealD *cloudcov, - RealD *windspeed, - RealD *r_humidity, + double *cloudcov, + double *windspeed, + double *r_humidity, TimeInt cum_monthdays[], TimeInt days_in_month[], LOG_INFO *LogInfo ) { - unsigned int yearIndex, year; + unsigned int yearIndex; + unsigned int year; /* Interpolation is to be in base0 in `interpolate_monthlyValues()` */ Bool interpAsBase1 = swFALSE; @@ -675,7 +705,7 @@ void readAllWeather( year = yearIndex + startYear; // Set all daily weather values to missing - _clear_hist_weather(allHist[yearIndex]); + clear_hist_weather(allHist[yearIndex]); // Update yearly day/month information needed when interpolating // cloud cover, wind speed, and relative humidity if necessary @@ -714,7 +744,7 @@ void readAllWeather( // Read daily weather values from disk if (!use_weathergenerator_only) { - _read_weather_hist( + read_weather_hist( year, allHist[yearIndex], weather_prefix, @@ -754,7 +784,8 @@ void finalizeAllWeather( LOG_INFO *LogInfo ) { - unsigned int day, yearIndex; + unsigned int day; + unsigned int yearIndex; // Impute missing values generateMissingWeather( @@ -859,22 +890,25 @@ minimum and maximum air temperature. */ void scaleAllWeather( SW_WEATHER_HIST **allHist, - int startYear, + unsigned int startYear, unsigned int n_years, double *scale_temp_max, double *scale_temp_min, double *scale_precip, double *scale_skyCover, - double *scale_wind, + const double *scale_wind, double *scale_rH, - double *scale_actVapPress, - double *scale_shortWaveRad, + const double *scale_actVapPress, + const double *scale_shortWaveRad, TimeInt cum_monthdays[], TimeInt days_in_month[] ) { - int year, month; - unsigned int yearIndex, numDaysYear, day; + unsigned int year; + unsigned int month; + unsigned int yearIndex; + unsigned int numDaysYear; + unsigned int day; Bool trivial = swTRUE; @@ -1025,25 +1059,37 @@ this requires that appropriate structures are initialized. void generateMissingWeather( SW_MARKOV *SW_Markov, SW_WEATHER_HIST **allHist, - int startYear, + unsigned int startYear, unsigned int n_years, unsigned int method, unsigned int optLOCF_nMax, LOG_INFO *LogInfo ) { - int year; - unsigned int yearIndex, numDaysYear, day, iMissing; - - double yesterdayPPT = 0., yesterdayTempMin = 0., yesterdayTempMax = 0., - yesterdayCloudCov = 0., yesterdayWindSpeed = 0., - yesterdayRelHum = 0., yesterdayShortWR = 0., yesterdayActVP = 0.; + unsigned int year; + unsigned int yearIndex; + unsigned int numDaysYear; + unsigned int day; + unsigned int iMissing; + + double yesterdayPPT = 0.; + double yesterdayTempMin = 0.; + double yesterdayTempMax = 0.; + double yesterdayCloudCov = 0.; + double yesterdayWindSpeed = 0.; + double yesterdayRelHum = 0.; + double yesterdayShortWR = 0.; + double yesterdayActVP = 0.; Bool any_missing; - Bool missing_Tmax = swFALSE, missing_Tmin = swFALSE, missing_PPT = swFALSE, - missing_CloudCov = swFALSE, missing_WindSpeed = swFALSE, - missing_RelHum = swFALSE, missing_ActVP = swFALSE, - missing_ShortWR = swFALSE; + Bool missing_Tmax = swFALSE; + Bool missing_Tmin = swFALSE; + Bool missing_PPT = swFALSE; + Bool missing_CloudCov = swFALSE; + Bool missing_WindSpeed = swFALSE; + Bool missing_RelHum = swFALSE; + Bool missing_ActVP = swFALSE; + Bool missing_ShortWR = swFALSE; // Pass through method: return early @@ -1203,10 +1249,13 @@ crash. void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { // Initialize any variables - TimeInt year, doy, numDaysInYear; + TimeInt year; + TimeInt doy; + TimeInt numDaysInYear; SW_WEATHER_HIST **weathHist = weather->allHist; - double dailyMinTemp, dailyMaxTemp; + double dailyMinTemp; + double dailyMaxTemp; // Loop through `allHist` years for (year = 0; year < weather->n_years; year++) { @@ -1235,7 +1284,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { doy + 1, year + weather->startYear ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if ((!missing(dailyMaxTemp) && !missing(dailyMinTemp)) && ((dailyMinTemp > 100. || dailyMinTemp < -100.) || @@ -1253,7 +1302,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { doy, year + weather->startYear ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if (!missing(weathHist[year]->ppt[doy]) && weathHist[year]->ppt[doy] < 0) { @@ -1269,7 +1318,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { doy + 1, year + weather->startYear ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if (!missing(weathHist[year]->r_humidity_daily[doy]) && (weathHist[year]->r_humidity_daily[doy] < 0. || @@ -1286,7 +1335,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { "%f). ", weathHist[year]->r_humidity_daily[doy] ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if (!missing(weathHist[year]->cloudcov_daily[doy]) && (weathHist[year]->cloudcov_daily[doy] < 0. || @@ -1302,7 +1351,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { " not fall in the range [0, 100] (cloud cover = %f). ", weathHist[year]->cloudcov_daily[doy] ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if (!missing(weathHist[year]->windspeed_daily[doy]) && weathHist[year]->windspeed_daily[doy] < 0.) { @@ -1318,7 +1367,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { doy + 1, year + weather->startYear ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if (!missing(weathHist[year]->shortWaveRad[doy]) && weathHist[year]->shortWaveRad[doy] < 0.) { @@ -1334,7 +1383,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { doy + 1, year + weather->startYear ); - return; // Exit function prematurely due to error + // Will exit function prematurely due to error } else if (!missing(weathHist[year]->actualVaporPressure[doy]) && weathHist[year]->actualVaporPressure[doy] < 0.) { @@ -1351,6 +1400,10 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { doy + 1, year + weather->startYear ); + // Will exit function prematurely due to error + } + + if (LogInfo->stopRun) { return; // Exit function prematurely due to error } } @@ -1361,7 +1414,7 @@ void checkAllWeather(SW_WEATHER *weather, LOG_INFO *LogInfo) { @brief Clears weather history. @note Used by rSOILWAT2 */ -void _clear_hist_weather(SW_WEATHER_HIST *yearWeather) { +void clear_hist_weather(SW_WEATHER_HIST *yearWeather) { /* --------------------------------------------------- */ TimeInt d; @@ -1537,7 +1590,7 @@ void deallocateAllWeather(SW_WEATHER_HIST **allHist, unsigned int n_years) { } } - free(allHist); + free((void *) allHist); allHist = NULL; } } @@ -1579,7 +1632,7 @@ void SW_WTH_init_run(SW_WEATHER *SW_Weather) { void SW_WTH_new_day( SW_WEATHER *SW_Weather, SW_SITE *SW_Site, - RealD snowpack[], + double snowpack[], TimeInt doy, TimeInt year, LOG_INFO *LogInfo @@ -1600,8 +1653,8 @@ void SW_WTH_new_day( SW_WEATHER_NOW *wn = &SW_Weather->now; /* Indices to today's weather record in `allHist` */ - TimeInt doy0 = doy - 1, - doy1 = doy; // Used for call to SW_SWC_adjust_snow() + TimeInt doy0 = doy - 1; + TimeInt doy1 = doy; // Used for call to SW_SWC_adjust_snow() TimeInt yearIndex = year - SW_Weather->startYear; /* @@ -1685,22 +1738,42 @@ void SW_WTH_new_day( @param[in,out] SW_Weather Struct of type SW_WEATHER holding all relevant information pretaining to meteorological input data @param[in] InFiles Array of program in/output files -@param[out] _weather_prefix File name of weather data without extension. +@param[out] weather_prefix File name of weather data without extension. @param[out] LogInfo Holds information on warnings and errors */ void SW_WTH_setup( SW_WEATHER *SW_Weather, char *InFiles[], - char *_weather_prefix, + char *weather_prefix, LOG_INFO *LogInfo ) { /* =================================================== */ const int nitems = 35; FILE *f; - int lineno = 0, month, x; - RealF sppt, stmax, stmin; - RealF sky, wind, rH, actVP, shortWaveRad; + int lineno = 0; + int month; + int x; + int index; + int resSNP; + double sppt; + double stmax; + double stmin; + double sky; + double wind; + double rH; + double actVP; + double shortWaveRad; char inbuf[MAX_FILENAMESIZE]; + int inBufintRes = 0; + double inBufdoubleRes = 0.; + + char weathInputStrs[9][20] = {{'\0'}}; + double *inDoubleVals[8] = { + &sppt, &stmax, &stmin, &sky, &wind, &rH, &actVP, &shortWaveRad + }; + const int numInDefaultVars = 9; + + Bool doIntConv; Bool *dailyInputFlags = SW_Weather->dailyInputFlags; @@ -1711,22 +1784,35 @@ void SW_WTH_setup( } while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { + doIntConv = (Bool) (lineno <= 22 && (lineno != 1 && lineno != 2)); + + if (lineno <= 22) { + if (doIntConv) { + inBufintRes = sw_strtoi(inbuf, MyFileName, LogInfo); + } else { + inBufdoubleRes = sw_strtod(inbuf, MyFileName, LogInfo); + } + + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (lineno) { case 0: - SW_Weather->use_snow = itob(atoi(inbuf)); + SW_Weather->use_snow = itob(inBufintRes); break; case 1: - SW_Weather->pct_snowdrift = atoi(inbuf); + SW_Weather->pct_snowdrift = inBufdoubleRes; break; case 2: - SW_Weather->pct_snowRunoff = atoi(inbuf); + SW_Weather->pct_snowRunoff = inBufdoubleRes; break; case 3: - x = atoi(inbuf); SW_Weather->use_weathergenerator_only = swFALSE; - switch (x) { + switch (inBufintRes) { case 0: // As is SW_Weather->generateWeatherMethod = 0; @@ -1749,92 +1835,92 @@ void SW_WTH_setup( break; default: - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, - "%s : Bad missing weather method %d.", + "%s : Requested weather generator method '%d' is not " + "implemented.", MyFileName, - x + inBufintRes ); - return; // Exit function prematurely due to error + goto closeFile; } break; case 4: - SW_Weather->rng_seed = atoi(inbuf); + SW_Weather->rng_seed = inBufintRes; break; case 5: - SW_Weather->use_cloudCoverMonthly = itob(atoi(inbuf)); + SW_Weather->use_cloudCoverMonthly = itob(inBufintRes); break; case 6: - SW_Weather->use_windSpeedMonthly = itob(atoi(inbuf)); + SW_Weather->use_windSpeedMonthly = itob(inBufintRes); break; case 7: - SW_Weather->use_humidityMonthly = itob(atoi(inbuf)); + SW_Weather->use_humidityMonthly = itob(inBufintRes); break; case 8: - SW_Weather->dailyInputFlags[TEMP_MAX] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[TEMP_MAX] = itob(inBufintRes); break; case 9: - SW_Weather->dailyInputFlags[TEMP_MIN] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[TEMP_MIN] = itob(inBufintRes); break; case 10: - SW_Weather->dailyInputFlags[PPT] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[PPT] = itob(inBufintRes); break; case 11: - SW_Weather->dailyInputFlags[CLOUD_COV] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[CLOUD_COV] = itob(inBufintRes); break; case 12: - SW_Weather->dailyInputFlags[WIND_SPEED] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[WIND_SPEED] = itob(inBufintRes); break; case 13: - SW_Weather->dailyInputFlags[WIND_EAST] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[WIND_EAST] = itob(inBufintRes); break; case 14: - SW_Weather->dailyInputFlags[WIND_NORTH] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[WIND_NORTH] = itob(inBufintRes); break; case 15: - SW_Weather->dailyInputFlags[REL_HUMID] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[REL_HUMID] = itob(inBufintRes); break; case 16: - SW_Weather->dailyInputFlags[REL_HUMID_MAX] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[REL_HUMID_MAX] = itob(inBufintRes); break; case 17: - SW_Weather->dailyInputFlags[REL_HUMID_MIN] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[REL_HUMID_MIN] = itob(inBufintRes); break; case 18: - SW_Weather->dailyInputFlags[SPEC_HUMID] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[SPEC_HUMID] = itob(inBufintRes); break; case 19: - SW_Weather->dailyInputFlags[TEMP_DEWPOINT] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[TEMP_DEWPOINT] = itob(inBufintRes); break; case 20: - SW_Weather->dailyInputFlags[ACTUAL_VP] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[ACTUAL_VP] = itob(inBufintRes); break; case 21: - SW_Weather->dailyInputFlags[SHORT_WR] = itob(atoi(inbuf)); + SW_Weather->dailyInputFlags[SHORT_WR] = itob(inBufintRes); break; case 22: - SW_Weather->desc_rsds = atoi(inbuf); + SW_Weather->desc_rsds = inBufintRes; break; @@ -1845,24 +1931,37 @@ void SW_WTH_setup( x = sscanf( inbuf, - "%d %f %f %f %f %f %f %f %f", - &month, - &sppt, - &stmax, - &stmin, - &sky, - &wind, - &rH, - &actVP, - &shortWaveRad + "%19s %19s %19s %19s %19s %19s %19s %19s %19s", + weathInputStrs[0], + weathInputStrs[1], + weathInputStrs[2], + weathInputStrs[3], + weathInputStrs[4], + weathInputStrs[5], + weathInputStrs[6], + weathInputStrs[7], + weathInputStrs[8] ); - if (x != 9) { - CloseFile(&f, LogInfo); + if (x != numInDefaultVars) { LogError( LogInfo, LOGERROR, "%s : Bad record %d.", MyFileName, lineno ); - return; // Exit function prematurely due to error + goto closeFile; + } + + for (index = 0; index < numInDefaultVars; index++) { + if (index == 0) { + month = + sw_strtoi(weathInputStrs[index], MyFileName, LogInfo); + } else { + *(inDoubleVals[index - 1]) = + sw_strtod(weathInputStrs[index], MyFileName, LogInfo); + } + + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } } month--; // convert to base0 @@ -1879,8 +1978,21 @@ void SW_WTH_setup( lineno++; } - strcpy(SW_Weather->name_prefix, _weather_prefix); - CloseFile(&f, LogInfo); + resSNP = snprintf( + SW_Weather->name_prefix, + sizeof SW_Weather->name_prefix, + "%s", + weather_prefix + ); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof SW_Weather->name_prefix)) { + LogError( + LogInfo, + LOGERROR, + "Weather input path name is too long: '%s'.", + weather_prefix + ); + return; // Exit function prematurely due to error + } if (lineno < nitems) { LogError(LogInfo, LOGERROR, "%s : Too few input lines.", MyFileName); @@ -1901,6 +2013,8 @@ void SW_WTH_setup( dailyInputFlags, LogInfo ); + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -1913,7 +2027,7 @@ void SW_WTH_setup( @param[out] n_input_forcings The number of active daily input variables. */ void set_dailyInputIndices( - Bool dailyInputFlags[MAX_INPUT_COLUMNS], + const Bool dailyInputFlags[MAX_INPUT_COLUMNS], unsigned int dailyInputIndices[MAX_INPUT_COLUMNS], unsigned int *n_input_forcings ) { @@ -1944,7 +2058,7 @@ void set_dailyInputIndices( * Turn off necessary flags. This happens after the calculation of input indices due to the fact that setting before calculating may result in an incorrect `n_input_forcings` in SW_WEATHER, and unexpectedly - crash the program in `_read_weather_hist()`. + crash the program in `read_weather_hist()`. * Check if monthly flags have been chosen to override daily flags. * Aside from checking for purely a monthly flag, we must make sure we have @@ -2141,13 +2255,13 @@ Format of a input file (white-space separated values): specifying what variable has daily input on disk @param[out] LogInfo Holds information on warnings and errors */ -void _read_weather_hist( +void read_weather_hist( TimeInt year, SW_WEATHER_HIST *yearWeather, char weather_prefix[], unsigned int n_input_forcings, - unsigned int *dailyInputIndices, - Bool *dailyInputFlags, + const unsigned int *dailyInputIndices, + const Bool *dailyInputFlags, LOG_INFO *LogInfo ) { /* =================================================== */ @@ -2166,11 +2280,13 @@ void _read_weather_hist( */ FILE *f; - unsigned int x, lineno = 0; - int doy; - // TimeInt mon, j, k = 0; - // RealF acc = 0.0; - RealD weathInput[MAX_INPUT_COLUMNS]; + unsigned int x; + unsigned int lineno = 0; + unsigned int index; + int doy = 0; + int resSNP; + + double weathInput[MAX_INPUT_COLUMNS]; Bool hasMaxMinTemp = (Bool) (dailyInputFlags[TEMP_MAX] && dailyInputFlags[TEMP_MIN]); @@ -2185,14 +2301,33 @@ void _read_weather_hist( (Bool) (hasMaxMinRelHumid || dailyInputFlags[REL_HUMID] || dailyInputFlags[SPEC_HUMID] || dailyInputFlags[ACTUAL_VP]); - double es, e, relHum, tempSlope, svpVal; + double es; + double e; + double relHum; + double tempSlope; + double svpVal; - char fname[MAX_FILENAMESIZE], inbuf[MAX_FILENAMESIZE]; + char fname[MAX_FILENAMESIZE]; + char inbuf[MAX_FILENAMESIZE]; + + char weathInStrs[15][20]; // Create file name: `[weather-file prefix].[year]` - snprintf(fname, MAX_FILENAMESIZE, "%s.%4d", weather_prefix, year); + resSNP = snprintf(fname, sizeof fname, "%s.%4d", weather_prefix, year); + + if (resSNP < 0 || (unsigned) resSNP >= (sizeof fname)) { + LogError( + LogInfo, + LOGERROR, + "Weather input file name is too long for year = %d", + year + ); + return; // Exit function prematurely due to error + } - if (NULL == (f = fopen(fname, "r"))) { + f = fopen(fname, "r"); + if (isnull(f)) { + // no weather input file --> use generator return; } @@ -2200,26 +2335,26 @@ void _read_weather_hist( lineno++; x = sscanf( inbuf, - "%d %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &doy, - &weathInput[0], - &weathInput[1], - &weathInput[2], - &weathInput[3], - &weathInput[4], - &weathInput[5], - &weathInput[6], - &weathInput[7], - &weathInput[8], - &weathInput[9], - &weathInput[10], - &weathInput[11], - &weathInput[12], - &weathInput[13] + "%19s %19s %19s %19s %19s %19s %19s %19s %19s %19s " + "%19s %19s %19s %19s %19s", + weathInStrs[0], + weathInStrs[1], + weathInStrs[2], + weathInStrs[3], + weathInStrs[4], + weathInStrs[5], + weathInStrs[6], + weathInStrs[7], + weathInStrs[8], + weathInStrs[9], + weathInStrs[10], + weathInStrs[11], + weathInStrs[12], + weathInStrs[13], + weathInStrs[14] ); if (x != n_input_forcings + 1) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -2228,10 +2363,9 @@ void _read_weather_hist( lineno, doy ); - return; // Exit function prematurely due to error + goto closeFile; } if (x > MAX_INPUT_COLUMNS + 1) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -2240,10 +2374,23 @@ void _read_weather_hist( lineno, doy ); - return; // Exit function prematurely due to error + goto closeFile; + } + + for (index = 0; index < n_input_forcings + 1; index++) { + if (index == 0) { + doy = sw_strtoi(weathInStrs[index], fname, LogInfo); + } else { + weathInput[index - 1] = + sw_strtod(weathInStrs[index], fname, LogInfo); + } + + if (LogInfo->stopRun) { + goto closeFile; + } } + if (doy < 1 || doy > MAX_DAYS) { - CloseFile(&f, LogInfo); LogError( LogInfo, LOGERROR, @@ -2251,7 +2398,7 @@ void _read_weather_hist( fname, lineno ); - return; // Exit function prematurely due to error + goto closeFile; } /* --- Make the assignments ---- */ @@ -2455,7 +2602,7 @@ void _read_weather_hist( } */ - fclose(f); +closeFile: { CloseFile(&f, LogInfo); } } void initializeClimatePtrs( @@ -2495,13 +2642,13 @@ void initializeMonthlyClimatePtrs(SW_CLIMATE_YEARLY *climateOutput) { } void allocateClimateStructs( - int numYears, + unsigned int numYears, SW_CLIMATE_YEARLY *climateOutput, SW_CLIMATE_CLIM *climateAverages, LOG_INFO *LogInfo ) { - int month; + unsigned int month; initializeClimatePtrs(climateOutput, climateAverages); @@ -2663,8 +2810,10 @@ void deallocateClimateStructs( SW_CLIMATE_YEARLY *climateOutput, SW_CLIMATE_CLIM *climateAverages ) { - int month, pointer; - const int numSinglePtrs = 14, numDoublePtrs = 4; + int month; + int pointer; + const int numSinglePtrs = 14; + const int numDoublePtrs = 4; double *singlePtrs[] = { climateOutput->PPT_cm, @@ -2708,7 +2857,7 @@ void deallocateClimateStructs( } } - free(doublePtrs[pointer]); + free((void *) doublePtrs[pointer]); } } } diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 635bf4ec2..650f7a422 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -16,7 +16,7 @@ #include // for NAN, ceil, isnan #include // for NC_NOERR, nc_close, NC_DOUBLE #include // for size_t, NULL, snprintf, sscanf -#include // for free, atof, atoi +#include // for free, strtod #include // for strcmp, strlen, strstr, memcpy #if defined(SWUDUNITS) @@ -47,7 +47,7 @@ const int times[] = {MAX_DAYS - 1, MAX_WEEKS, MAX_MONTHS, 1}; -static const char *possKeys[SW_OUTNKEYS][SW_OUTNMAXVARS] = { +static const char *const possKeys[SW_OUTNKEYS][SW_OUTNMAXVARS] = { {NULL}, // WTHR {"TEMP__temp_max", "TEMP__temp_min", @@ -138,7 +138,7 @@ static const char *possKeys[SW_OUTNKEYS][SW_OUTNMAXVARS] = { "BIOMASS__LAI"} }; -static const char *SWVarUnits[SW_OUTNKEYS][SW_OUTNMAXVARS] = { +static const char *const SWVarUnits[SW_OUTNKEYS][SW_OUTNMAXVARS] = { {NULL}, /* WTHR */ {"degC", "degC", "degC", "degC", "degC", "degC"}, /* TEMP */ {"cm", "cm", "cm", "cm", "cm"}, /* PRECIP */ @@ -233,13 +233,26 @@ static void nc_read_atts( Bool hasKeys[NUM_ATT_IN_KEYS] = {swFALSE}; FILE *f; - char inbuf[LARGE_VALUE], value[LARGE_VALUE]; + char inbuf[LARGE_VALUE]; + char value[LARGE_VALUE]; char key[35]; // 35 - Max key size char *MyFileName; int keyID; int n; - float num1 = 0, num2 = 0; - Bool geoCRSFound = swFALSE, projCRSFound = swFALSE; + int scanRes; + double num1 = 0; + double num2 = 0; + Bool geoCRSFound = swFALSE; + Bool projCRSFound = swFALSE; + Bool infVal = swFALSE; + + double inBufdoubleRes = 0.; + int inBufintRes = 0; + char numOneStr[20]; + char numTwoStr[20]; + + Bool doIntConv; + Bool doDoubleConv; MyFileName = PathInfo->InFiles[eNCInAtt]; f = OpenFile(MyFileName, "r", LogInfo); @@ -254,20 +267,62 @@ static void nc_read_atts( } while (GetALine(f, inbuf, LARGE_VALUE)) { - sscanf(inbuf, "%34s %s", key, value); + + scanRes = sscanf(inbuf, "%34s %s", key, value); + + if (scanRes < 2) { + LogError( + LogInfo, + LOGERROR, + "Not enough values for a valid key-value pair in %s.", + MyFileName + ); + goto closeFile; + } // Check if the key is "long_name" or "crs_wkt" if (strstr(key, "long_name") != NULL || strstr(key, "crs_wkt") != NULL) { // Reread the like and get the entire value (includes spaces) - sscanf(inbuf, "%34s %[^\n]", key, value); + scanRes = sscanf(inbuf, "%34s %[^\n]", key, value); + if (scanRes < 2) { + LogError( + LogInfo, + LOGERROR, + "Not enough values for a valid key-value pair in %s.", + MyFileName + ); + goto closeFile; + } } keyID = key_to_id(key, possibleKeys, NUM_ATT_IN_KEYS); set_hasKey(keyID, possibleKeys, hasKeys, LogInfo); // set_hasKey() does not produce errors, only warnings possible + /* Check to see if the line number contains a double or integer value */ + doIntConv = (Bool) (keyID >= 23 && keyID <= 25); + doDoubleConv = (Bool) ((keyID >= 9 && keyID <= 11) || + (keyID >= 15 && keyID <= 17) || + (keyID >= 21 && keyID <= 22)); + + if (doIntConv || doDoubleConv) { + if (doIntConv) { + infVal = (Bool) (Str_CompareI(value, (char *) "Inf") == 0); + + if (!infVal) { + inBufintRes = sw_strtoi(value, MyFileName, LogInfo); + } + } else { + inBufdoubleRes = sw_strtod(value, MyFileName, LogInfo); + } + + if (LogInfo->stopRun) { + goto closeFile; + } + } + switch (keyID) { case 0: SW_netCDF->title = Str_Dup(value, LogInfo); @@ -298,8 +353,7 @@ static void nc_read_atts( "geographic and projected.", value ); - CloseFile(&f, LogInfo); - return; // Exit function prematurely due to error + goto closeFile; } break; case 6: @@ -313,13 +367,13 @@ static void nc_read_atts( SW_netCDF->crs_geogsc.crs_wkt = Str_Dup(value, LogInfo); break; case 9: - SW_netCDF->crs_geogsc.longitude_of_prime_meridian = atof(value); + SW_netCDF->crs_geogsc.longitude_of_prime_meridian = inBufdoubleRes; break; case 10: - SW_netCDF->crs_geogsc.semi_major_axis = atof(value); + SW_netCDF->crs_geogsc.semi_major_axis = inBufdoubleRes; break; case 11: - SW_netCDF->crs_geogsc.inverse_flattening = atof(value); + SW_netCDF->crs_geogsc.inverse_flattening = inBufdoubleRes; break; case 12: SW_netCDF->crs_projsc.long_name = Str_Dup(value, LogInfo); @@ -332,13 +386,13 @@ static void nc_read_atts( SW_netCDF->crs_projsc.crs_wkt = Str_Dup(value, LogInfo); break; case 15: - SW_netCDF->crs_projsc.longitude_of_prime_meridian = atof(value); + SW_netCDF->crs_projsc.longitude_of_prime_meridian = inBufdoubleRes; break; case 16: - SW_netCDF->crs_projsc.semi_major_axis = atof(value); + SW_netCDF->crs_projsc.semi_major_axis = inBufdoubleRes; break; case 17: - SW_netCDF->crs_projsc.inverse_flattening = atof(value); + SW_netCDF->crs_projsc.inverse_flattening = inBufdoubleRes; break; case 18: SW_netCDF->crs_projsc.datum = Str_Dup(value, LogInfo); @@ -349,39 +403,67 @@ static void nc_read_atts( case 20: // Re-scan for 1 or 2 values of standard parallel(s) // the user may separate values by white-space, comma, etc. - n = sscanf(inbuf, "%34s %f%*[^-.0123456789]%f", key, &num1, &num2); + n = sscanf( + inbuf, + "%34s %19s%*[^-.0123456789]%19s", + key, + numOneStr, + numTwoStr + ); + + if (n < 2) { + LogError( + LogInfo, + LOGERROR, + "Not enough values to read in for the standard parallel(s)." + ); + goto closeFile; + } + + num1 = sw_strtod(numOneStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } + + num2 = sw_strtod(numTwoStr, MyFileName, LogInfo); + if (LogInfo->stopRun) { + goto closeFile; + } SW_netCDF->crs_projsc.standard_parallel[0] = num1; SW_netCDF->crs_projsc.standard_parallel[1] = (n == 3) ? num2 : NAN; break; case 21: - SW_netCDF->crs_projsc.longitude_of_central_meridian = atof(value); + SW_netCDF->crs_projsc.longitude_of_central_meridian = + inBufdoubleRes; break; case 22: - SW_netCDF->crs_projsc.latitude_of_projection_origin = atof(value); + SW_netCDF->crs_projsc.latitude_of_projection_origin = + inBufdoubleRes; break; case 23: - SW_netCDF->crs_projsc.false_easting = atoi(value); + SW_netCDF->crs_projsc.false_easting = inBufintRes; break; case 24: - SW_netCDF->crs_projsc.false_northing = atoi(value); + SW_netCDF->crs_projsc.false_northing = inBufintRes; break; case 25: - if (Str_CompareI(value, (char *) "Inf") != 0) { - SW_netCDF->strideOutYears = atoi(value); + if (!infVal) { + SW_netCDF->strideOutYears = inBufintRes; if (SW_netCDF->strideOutYears <= 0) { LogError( LogInfo, LOGERROR, "The value for 'strideOutYears' <= 0" ); - return; // Exit function due to invalid input + goto closeFile; } } break; case 26: - SW_netCDF->baseCalendarYear = atoi(value); + SW_netCDF->baseCalendarYear = inBufintRes; break; case KEY_NOT_FOUND: + default: LogError( LogInfo, LOGWARN, @@ -393,20 +475,17 @@ static void nc_read_atts( } if (LogInfo->stopRun) { - CloseFile(&f, LogInfo); - return; // Exist function prematurely due to error + goto closeFile; } } - CloseFile(&f, LogInfo); - // Check if all required input was provided check_requiredKeys( hasKeys, requiredKeys, possibleKeys, NUM_ATT_IN_KEYS, LogInfo ); if (LogInfo->stopRun) { - return; // Exit function prematurely due to error + goto closeFile; } @@ -420,7 +499,7 @@ static void nc_read_atts( PathInfo->InFiles[eNCInAtt], (SW_netCDF->primary_crs_is_geographic) ? "geographic" : "projected" ); - return; // Exit function prematurely due to error + goto closeFile; } if (projCRSFound && !geoCRSFound) { @@ -434,13 +513,15 @@ static void nc_read_atts( "'projected' with a geographic CRS.", PathInfo->InFiles[eNCInAtt] ); - return; // Exit function prematurely due to error + goto closeFile; } SW_netCDF->coordinate_system = (SW_netCDF->primary_crs_is_geographic) ? Str_Dup(SW_netCDF->crs_geogsc.long_name, LogInfo) : Str_Dup(SW_netCDF->crs_projsc.long_name, LogInfo); + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -448,10 +529,11 @@ static void nc_read_atts( it's respective numeric values */ static void get_2d_output_key( - char *varKey, OutKey *outKey, int *outVarNum, IntUS nvar_OUT[] + char *varKey, OutKey *outKey, int *outVarNum, const IntUS nvar_OUT[] ) { - int k, varNum; + int k; + int varNum; const int establSize = 6; *outKey = eSW_NoKey; @@ -463,12 +545,14 @@ static void get_2d_output_key( ForEachOutKey(k) { if (k != eSW_Estab) { for (varNum = 0; varNum < nvar_OUT[k]; varNum++) { - if (strcmp(possKeys[k][varNum], varKey) == 0) { + if (!isnull(possKeys[k][varNum])) { + if (strcmp(possKeys[k][varNum], varKey) == 0) { - *outKey = (OutKey) k; - *outVarNum = varNum; + *outKey = (OutKey) k; + *outVarNum = varNum; - return; + return; + } } } } @@ -536,7 +620,9 @@ static void get_str_att_val( LOG_INFO *LogInfo ) { - int varID = 0, attCallRes, attLenCallRes; + int varID = 0; + int attCallRes; + int attLenCallRes; size_t attLen = 0; get_var_identifier(ncFileID, varName, &varID, LogInfo); if (LogInfo->stopRun) { @@ -553,7 +639,6 @@ static void get_str_att_val( attName, varName ); - return; // Exit function prematurely due to error } else if (attLenCallRes != NC_NOERR) { LogError( LogInfo, @@ -565,6 +650,11 @@ static void get_str_att_val( ); } + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + attCallRes = nc_get_att_text(ncFileID, varID, attName, strVal); if (attCallRes != NC_NOERR) { LogError( @@ -598,7 +688,8 @@ static void get_double_att_val( LOG_INFO *LogInfo ) { - int varID = 0, attCallRes; + int varID = 0; + int attCallRes; get_var_identifier(ncFileID, varName, &varID, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error @@ -1077,11 +1168,11 @@ static void write_double_vals( @param[out] LogInfo Holds information on warnings and errors */ static void write_string_vals( - int ncFileID, int varID, const char **varVals, LOG_INFO *LogInfo + int ncFileID, int varID, const char *const varVals[], LOG_INFO *LogInfo ) { - - if (nc_put_var_string(ncFileID, varID, &varVals[0]) != NC_NOERR) { + if (nc_put_var_string(ncFileID, varID, (const char **) &varVals[0]) != + NC_NOERR) { LogError(LogInfo, LOGERROR, "Could not write string values."); } } @@ -1098,12 +1189,17 @@ static void fill_prog_netCDF_vals(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { int domVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCdom]; int progVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCprog]; unsigned int domStatus; - unsigned long suid, ncSuid[2], nSUIDs = SW_Domain->nSUIDs; - unsigned long nDimY = SW_Domain->nDimY, nDimX = SW_Domain->nDimX; + unsigned long suid; + unsigned long ncSuid[2]; + unsigned long nSUIDs = SW_Domain->nSUIDs; + unsigned long nDimY = SW_Domain->nDimY; + unsigned long nDimX = SW_Domain->nDimX; int progFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCprog]; int domFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCdom]; - size_t start1D[] = {0}, start2D[] = {0, 0}; - size_t count1D[] = {nSUIDs}, count2D[] = {nDimY, nDimX}; + size_t start1D[] = {0}; + size_t start2D[] = {0, 0}; + size_t count1D[] = {nSUIDs}; + size_t count2D[] = {nDimY, nDimX}; size_t *start = (strcmp(SW_Domain->DomainType, "s") == 0) ? start1D : start2D; size_t *count = @@ -1147,7 +1243,7 @@ static void fill_prog_netCDF_vals(SW_DOMAIN *SW_Domain, LOG_INFO *LogInfo) { static void create_netCDF_dim( const char *dimName, unsigned long size, - int *ncFileID, + const int *ncFileID, int *dimID, LOG_INFO *LogInfo ) { @@ -1178,15 +1274,16 @@ static void create_netCDF_var( int *varID, const char *varName, int *dimIDs, - int *ncFileID, + const int *ncFileID, int varType, int numDims, LOG_INFO *LogInfo ) { // Deflate information - int shuffle = 1, deflate = 1; // 0 or 1 - int level = 5; // 0 to 9 + int shuffle = 1; // 0 or 1 + int deflate = 1; // 0 or 1 + int level = 5; // 0 to 9 if (nc_def_var(*ncFileID, varName, varType, numDims, dimIDs, varID) != NC_NOERR) { @@ -1271,7 +1368,7 @@ memory for writing out values */ static void alloc_netCDF_domain_vars( Bool domTypeIsSite, - int nSUIDs, + unsigned long nSUIDs, unsigned int numY, unsigned int numX, double **valsY, @@ -1284,8 +1381,11 @@ static void alloc_netCDF_domain_vars( double **vars[] = {valsY, valsX}; double **bndsVars[] = {valsYBnds, valsXBnds}; - const int numVars = 2, numBnds = 2; - int varNum, bndVarNum, numVals; + const int numVars = 2; + const int numBnds = 2; + unsigned int varNum; + unsigned int bndVarNum; + unsigned int numVals; for (varNum = 0; varNum < numVars; varNum++) { numVals = (varNum % 2 == 0) ? numY : numX; @@ -1302,7 +1402,7 @@ static void alloc_netCDF_domain_vars( numVals = (bndVarNum % 2 == 0) ? numY : numX; *(bndsVars[bndVarNum]) = (double *) Mem_Malloc( - numVals * numBnds * sizeof(double), + (size_t) (numVals * numBnds) * sizeof(double), "alloc_netCDF_domain_vars()", LogInfo ); @@ -1333,7 +1433,9 @@ static void alloc_outvars(char ****outkeyVars, int nVar, LOG_INFO *LogInfo) { if (nVar > 0) { - int index, varNum, attNum; + int index; + int varNum; + int attNum; // Allocate all memory for the variable information in the current // output key @@ -1354,9 +1456,9 @@ static void alloc_outvars(char ****outkeyVars, int nVar, LOG_INFO *LogInfo) { ); if (LogInfo->stopRun) { for (varNum = 0; varNum < index; varNum++) { - free((*outkeyVars)[varNum]); + free((void *) (*outkeyVars)[varNum]); } - free(*outkeyVars); + free((void *) *outkeyVars); return; // Exit function prematurely due to error } @@ -1504,15 +1606,22 @@ static void fill_domain_netCDF_vals( ) { Bool domTypeIsSite = (Bool) (strcmp(SW_Domain->DomainType, "s") == 0); - unsigned int suidNum, gridNum = 0, *domVals = NULL, bndsIndex; - double *valsY = NULL, *valsX = NULL; - double *valsYBnds = NULL, *valsXBnds = NULL; + unsigned int suidNum; + unsigned int gridNum = 0; + unsigned int *domVals = NULL; + unsigned int bndsIndex; + double *valsY = NULL; + double *valsX = NULL; + double *valsYBnds = NULL; + double *valsXBnds = NULL; size_t start[] = {0, 0}; size_t domCount[2]; // domCount: 2 - [#lat dim, #lon dim] or [#sites, 0] - size_t fillCountY[1], fillCountX[1]; + size_t fillCountY[1]; + size_t fillCountX[1]; size_t fillCountYBnds[] = {SW_Domain->nDimY, 2}; size_t fillCountXBnds[] = {SW_Domain->nDimX, 2}; - double resY, resX; + double resY; + double resX; unsigned int numX = (domTypeIsSite) ? SW_Domain->nDimS : SW_Domain->nDimX; unsigned int numY = (domTypeIsSite) ? SW_Domain->nDimS : SW_Domain->nDimY; @@ -1521,7 +1630,8 @@ static void fill_domain_netCDF_vals( size_t *fillCounts[] = { fillCountY, fillCountX, fillCountYBnds, fillCountXBnds }; - int numVars, varNum; + int numVars; + int varNum; alloc_netCDF_domain_vars( domTypeIsSite, @@ -1645,7 +1755,7 @@ static void fill_domain_netCDF_vals( */ static void fill_domain_netCDF_domain( const char *domainVarName, - int *domID, + int *domVarID, int domDims[], int domFileID, int nDomainDims, @@ -1670,10 +1780,16 @@ static void fill_domain_netCDF_domain( const int numAtts = 4; create_netCDF_var( - domID, domainVarName, domDims, &domFileID, NC_UINT, nDomainDims, LogInfo + domVarID, + domainVarName, + domDims, + &domFileID, + NC_UINT, + nDomainDims, + LogInfo ); - write_uint_att("_FillValue", NC_FILL_UINT, *domID, domFileID, LogInfo); + write_uint_att("_FillValue", NC_FILL_UINT, *domVarID, domFileID, LogInfo); if (LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -1681,7 +1797,11 @@ static void fill_domain_netCDF_domain( // Write all attributes to the domain variable for (attNum = 0; attNum < numAtts; attNum++) { write_str_att( - strAttNames[attNum], strAttVals[attNum], *domID, domFileID, LogInfo + strAttNames[attNum], + strAttVals[attNum], + *domVarID, + domFileID, + LogInfo ); if (LogInfo->stopRun) { @@ -1719,8 +1839,11 @@ static void fill_domain_netCDF_s( Bool primCRSIsGeo = SW_Domain->netCDFInfo.primary_crs_is_geographic; char *units = SW_Domain->netCDFInfo.crs_projsc.units; - const int numSiteAtt = 3, numLatAtt = 4, numLonAtt = 4; - const int numYAtt = 3, numXAtt = 3; + const int numSiteAtt = 3; + const int numLatAtt = 4; + const int numLonAtt = 4; + const int numYAtt = 3; + const int numXAtt = 3; // numVarsToWrite: Do or do not write "x" and "y" int numVarsToWrite = (primCRSIsGeo) ? 3 : 5; const char *attNames[][4] = { @@ -1743,7 +1866,8 @@ static void fill_domain_netCDF_s( int varIDs[5]; // 5 - Maximum number of variables to create const int numAtts[] = {numSiteAtt, numLatAtt, numLonAtt, numYAtt, numXAtt}; - int varNum, attNum; + int varNum; + int attNum; create_netCDF_dim("site", SW_Domain->nDimS, domFileID, sDimID, LogInfo); if (LogInfo->stopRun) { @@ -1846,7 +1970,9 @@ static void fill_domain_netCDF_xy( int bndsID = 0; int bndVarDims[2]; // Used for bound variables in the netCDF file - int dimNum, varNum, attNum; + int dimNum; + int varNum; + int attNum; const int numVars = (primCRSIsGeo) ? 2 : 4; // lat/lon or lat/lon + x/y vars const char *varNames[] = {"lat", "lon", "y", "x"}; @@ -1870,7 +1996,10 @@ static void fill_domain_netCDF_xy( units, "x_bnds"} }; - int numLatAtt = 5, numLonAtt = 5, numYAtt = 4, numXAtt = 4; + int numLatAtt = 5; + int numLonAtt = 5; + int numYAtt = 4; + int numXAtt = 4; int numAtts[] = {numLatAtt, numLonAtt, numYAtt, numXAtt}; const int numDims = 3; @@ -1992,11 +2121,14 @@ static void fill_domain_netCDF_xy( @param[out] LogInfo Holds information on warnings and errors */ static void fill_netCDF_with_proj_CRS_atts( - SW_CRS *crs_projsc, int *ncFileID, int proj_id, LOG_INFO *LogInfo + SW_CRS *crs_projsc, const int *ncFileID, int proj_id, LOG_INFO *LogInfo ) { - const int numStrAtts = 5, numDoubleAtts = 8; - int strAttNum, doubleAttNum, numValsToWrite; + const int numStrAtts = 5; + const int numDoubleAtts = 8; + int strAttNum; + int doubleAttNum; + int numValsToWrite; const char *strAttNames[] = { "long_name", "grid_mapping_name", "datum", "units", "crs_wkt" }; @@ -2074,13 +2206,15 @@ static void fill_netCDF_with_proj_CRS_atts( */ static void fill_netCDF_with_geo_CRS_atts( SW_CRS *crs_geogsc, - int *ncFileID, + const int *ncFileID, char *coord_sys, int geo_id, LOG_INFO *LogInfo ) { - int attNum, numStrAtts = 3, numDoubleAtts = 3; + int attNum; + int numStrAtts = 3; + int numDoubleAtts = 3; const int numValsToWrite = 1; const char *strAttNames[] = {"grid_mapping_name", "long_name", "crs_wkt"}; const char *doubleAttNames[] = { @@ -2149,7 +2283,7 @@ static void fill_netCDF_with_geo_CRS_atts( */ static void fill_netCDF_with_global_atts( SW_NETCDF *SW_netCDF, - int *ncFileID, + const int *ncFileID, const char *domType, const char *freqAtt, Bool isInputFile, @@ -2207,7 +2341,7 @@ static void fill_netCDF_with_global_atts( }; // Fill `sourceStr` and `creationDateStr` - snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); + (void) snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); timeStringISO8601(creationDateStr, sizeof creationDateStr); // Write out the necessary global attributes that are listed above @@ -2234,7 +2368,7 @@ static void fill_netCDF_with_global_atts( @param[in,out] LogInfo Holds information dealing with logfile output */ static void update_netCDF_global_atts( - int *ncFileID, + const int *ncFileID, const char *domType, const char *freqAtt, Bool isInputFile, @@ -2266,7 +2400,7 @@ static void update_netCDF_global_atts( }; // Fill `sourceStr` and `creationDateStr` - snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); + (void) snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); timeStringISO8601(creationDateStr, sizeof creationDateStr); // Write out the necessary global attributes that are listed above @@ -2301,7 +2435,8 @@ static void fill_netCDF_with_invariants( LOG_INFO *LogInfo ) { - int geo_id = 0, proj_id = 0; + int geo_id = 0; + int proj_id = 0; const char *fx = "fx"; create_netCDF_var( @@ -2355,12 +2490,15 @@ static void fill_netCDF_with_invariants( (e.g., 60 months in 5 years, or 731 days in 1980-1981) @param[in] pd Current output netCDF period */ -static double calc_timeSize( - int rangeStart, int rangeEnd, int baseTime, OutPeriod pd +static unsigned int calc_timeSize( + unsigned int rangeStart, + unsigned int rangeEnd, + unsigned int baseTime, + OutPeriod pd ) { - double numLeapYears = 0.0; - int year; + unsigned int numLeapYears = 0; + unsigned int year; if (pd == eSW_Day) { for (year = rangeStart; year < rangeEnd; year++) { @@ -2370,7 +2508,7 @@ static double calc_timeSize( } } - return (double) (baseTime * (rangeEnd - rangeStart)) + numLeapYears; + return baseTime * (rangeEnd - rangeStart) + numLeapYears; } /** @@ -2391,19 +2529,23 @@ the variable "time_bnds" and fills the variable "time" static void create_time_vars( int ncFileID, int dimIDs[], - int size, + unsigned int size, int dimVarID, - int startYr, + unsigned int startYr, double *startTime, OutPeriod pd, LOG_INFO *LogInfo ) { - double *bndsVals = NULL, *dimVarVals = NULL; - size_t numBnds = 2; - size_t start[] = {0, 0}, count[] = {(size_t) size, 0}; - int currYear = startYr; - int month = 0, week = 0, numDays = 0; + double *bndsVals = NULL; + double *dimVarVals = NULL; + const int numBnds = 2; + size_t start[] = {0, 0}; + size_t count[] = {(size_t) size, 0}; + unsigned int currYear = startYr; + unsigned int month = 0; + unsigned int week = 0; + unsigned int numDays = 0; int bndsID = 0; @@ -2422,7 +2564,7 @@ static void create_time_vars( } bndsVals = (double *) Mem_Malloc( - size * numBnds * sizeof(double), "create_time_vars", LogInfo + (size_t) (size * numBnds) * sizeof(double), "create_time_vars", LogInfo ); if (LogInfo->stopRun) { free(dimVarVals); @@ -2444,7 +2586,7 @@ static void create_time_vars( numDays = WKDAYS; } - currYear += (index % MAX_WEEKS == 0) ? 1.0 : 0.0; + currYear += (index % MAX_WEEKS == 0) ? 1 : 0; week = (week + 1) % MAX_WEEKS; break; @@ -2455,7 +2597,7 @@ static void create_time_vars( numDays = monthdays[month]; } - currYear += (index % MAX_MONTHS == 0) ? 1.0 : 0.0; + currYear += (index % MAX_MONTHS == 0) ? 1 : 0; month = (month + 1) % MAX_MONTHS; break; @@ -2512,16 +2654,19 @@ the variable "vertical_bnds" and fills the variable "vertical" static void create_vert_vars( int ncFileID, int dimIDs[], - int size, + unsigned int size, int dimVarID, Bool hasConsistentSoilLayerDepths, - double lyrDepths[], + const double lyrDepths[], LOG_INFO *LogInfo ) { - double *dimVarVals = NULL, *bndVals = NULL, lyrStart = 0.0; - size_t numBnds = 2; - size_t start[] = {0, 0}, count[] = {(size_t) size, 0}; + double *dimVarVals = NULL; + double *bndVals = NULL; + double lyrStart = 0.0; + const int numBnds = 2; + size_t start[] = {0, 0}; + size_t count[] = {(size_t) size, 0}; int bndIndex = 0; create_netCDF_var( @@ -2545,7 +2690,7 @@ static void create_vert_vars( } bndVals = (double *) Mem_Malloc( - size * numBnds * sizeof(double), "create_vert_vars", LogInfo + (size_t) (size * numBnds) * sizeof(double), "create_vert_vars", LogInfo ); if (LogInfo->stopRun) { free(dimVarVals); @@ -2555,8 +2700,9 @@ static void create_vert_vars( for (size_t index = 0; index < (size_t) size; index++) { // if hasConsistentSoilLayerDepths, // then use soil layer depth, else soil layer number - dimVarVals[index] = - (hasConsistentSoilLayerDepths) ? lyrDepths[index] : (index + 1); + dimVarVals[index] = (hasConsistentSoilLayerDepths) ? + lyrDepths[index] : + (double) (index + 1); bndVals[index * 2] = lyrStart; bndVals[index * 2 + 1] = dimVarVals[index]; @@ -2606,18 +2752,20 @@ if needed static void fill_dimVar( int ncFileID, int dimIDs[], - int size, + unsigned int size, int varID, Bool hasConsistentSoilLayerDepths, double lyrDepths[], double *startTime, int dimNum, - int startYr, + unsigned int startYr, OutPeriod pd, LOG_INFO *LogInfo ) { - const int vertInd = 0, timeInd = 1, pftInd = 2; + const int vertInd = 0; + const int timeInd = 1; + const int pftInd = 2; const int numBnds = 2; @@ -2688,22 +2836,26 @@ and fill the variable with the respective information */ static void create_output_dimVar( char *name, - int size, + unsigned int size, int ncFileID, int *dimID, Bool hasConsistentSoilLayerDepths, double lyrDepths[], double *startTime, - int baseCalendarYear, - int startYr, + unsigned int baseCalendarYear, + unsigned int startYr, OutPeriod pd, LOG_INFO *LogInfo ) { char *dimNames[3] = {(char *) "vertical", (char *) "time", (char *) "pft"}; - const int vertIndex = 0, timeIndex = 1, pftIndex = 2, timeUnitIndex = 2; + const int vertIndex = 0; + const int timeIndex = 1; + const int pftIndex = 2; + const int timeUnitIndex = 2; int dimNum; - int varID, index; + int varID; + int index; int dimIDs[2] = {0, 0}; int varType; double tempVal = 1.0; @@ -2729,6 +2881,15 @@ static void create_output_dimVar( break; } } + if (dimNum >= 3) { + LogError( + LogInfo, + LOGERROR, + "create_output_dimVar() does not support requested dimension '%s'.", + name + ); + return; // Exit function prematurely due to error + } varType = (dimNum == pftIndex) ? NC_STRING : NC_DOUBLE; @@ -2764,7 +2925,7 @@ static void create_output_dimVar( ); if (dimNum == timeIndex) { - snprintf( + (void) snprintf( outAttVals[timeIndex][timeUnitIndex], MAX_FILENAMESIZE, "days since %d-01-01 00:00:00", @@ -2775,8 +2936,11 @@ static void create_output_dimVar( if (dimNum == vertIndex && !hasConsistentSoilLayerDepths) { // Use soil layers as dimension variable values // because soil layer depths are not consistent across domain - snprintf(outAttVals[vertIndex][0], MAX_FILENAMESIZE, "soil layer"); - snprintf(outAttVals[vertIndex][2], MAX_FILENAMESIZE, "1"); + (void) sw_memccpy( + outAttVals[vertIndex][0], "soil layer", '\0', MAX_FILENAMESIZE + ); + (void + ) sw_memccpy(outAttVals[vertIndex][2], "1", '\0', MAX_FILENAMESIZE); } for (index = 0; index < numVarAtts[dimNum]; index++) { @@ -2830,28 +2994,31 @@ static void create_full_var( const char *varName, const char *attNames[], const char *attVals[], - int numAtts, + unsigned int numAtts, Bool hasConsistentSoilLayerDepths, double lyrDepths[], double *startTime, - int baseCalendarYear, - int startYr, + unsigned int baseCalendarYear, + unsigned int startYr, OutPeriod pd, LOG_INFO *LogInfo ) { - int dimArrSize = 0, index, varID = 0; + int dimArrSize = 0; + int varID = 0; + unsigned int index; int dimIDs[MAX_NUM_DIMS]; const char *latName = (dimExists("lat", *ncFileID)) ? "lat" : "y"; const char *lonName = (dimExists("lon", *ncFileID)) ? "lon" : "x"; Bool domTypeIsSites = (Bool) (strcmp(domType, "s") == 0); - int numConstDims = (domTypeIsSites) ? 1 : 2; + unsigned int numConstDims = (domTypeIsSites) ? 1 : 2; const char *thirdDim = (domTypeIsSites) ? "site" : latName; const char *constDimNames[] = {thirdDim, lonName}; const char *timeVertVegNames[] = {"time", "vertical", "pft"}; char *dimVarName; size_t timeVertVegVals[] = {timeSize, vertSize, pftSize}; - int numTimeVertVegVals = 3, varVal; + unsigned int numTimeVertVegVals = 3; + unsigned int varVal; for (index = 0; index < numConstDims; index++) { @@ -2938,19 +3105,31 @@ static int gather_var_attributes( OutSum sumType, LOG_INFO *LogInfo ) { - int fillSize = 0, varIndex; - char cellRedef[MAX_FILENAMESIZE], establOrginName[MAX_FILENAMESIZE]; + int fillSize = 0; + int varIndex; + int resSNP; + char cellRedef[MAX_FILENAMESIZE]; + char establOrginName[MAX_FILENAMESIZE]; // Determine attribute 'original_name' if (key == eSW_Estab) { - snprintf( + resSNP = snprintf( establOrginName, - MAX_FILENAMESIZE, + sizeof establOrginName, "%s__%s", SW_ESTAB, varInfo[VARNAME_INDEX] ); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof establOrginName)) { + LogError( + LogInfo, + LOGWARN, + "attribute 'original_name' of variable '%s' was truncated.", + varInfo[VARNAME_INDEX] + ); + } + resAtts[fillSize] = Str_Dup(establOrginName, LogInfo); if (LogInfo->stopRun) { return 0; // Exit function prematurely due to error @@ -2968,13 +3147,23 @@ static int gather_var_attributes( } if (pd > eSW_Day) { - snprintf( + resSNP = snprintf( cellRedef, - MAX_FILENAMESIZE, + sizeof cellRedef, "%s within days time: %s over days", resAtts[fillSize - 1], styp2longstr[sumType] ); + + if (resSNP < 0 || (unsigned) resSNP >= (sizeof cellRedef)) { + LogError( + LogInfo, + LOGWARN, + "attribute 'cell_methods' of variable '%s' was truncated.", + varInfo[VARNAME_INDEX] + ); + } + Str_ToLower(cellRedef, cellRedef); resAtts[fillSize - 1] = Str_Dup(cellRedef, LogInfo); if (LogInfo->stopRun) { @@ -3038,8 +3227,8 @@ static void create_output_file( IntUS npft[], Bool hasConsistentSoilLayerDepths, double lyrDepths[], - int originTimeSize, - int startYr, + unsigned int originTimeSize, + unsigned int startYr, int baseCalendarYear, double *startTime, LOG_INFO *LogInfo @@ -3066,7 +3255,7 @@ static void create_output_file( char *varName; char **varInfo; - snprintf(frequency, 9, "%s", pd2longstr[pd]); + (void) sw_memccpy(frequency, (char *) pd2longstr[pd], '\0', 9); Str_ToLower(frequency, frequency); @@ -3168,7 +3357,8 @@ static void get_vardim_write_counts( size_t count[], size_t *countTotal ) { - int dimIndex, ndimsp; + int dimIndex; + int ndimsp; int nSpaceDims = (strcmp(domType, "s") == 0) ? 1 : 2; /* Fill 1s into space dimensions (we write one site/xy-gridcell per run) */ @@ -3227,7 +3417,8 @@ static void check_counts_against_vardim( LOG_INFO *LogInfo ) { - int dimIndex, ndimsp; + int dimIndex; + int ndimsp; int nSpaceDims = dimExists("site", ncFileID) ? 1 : 2; int dimidsp[MAX_NUM_DIMS] = {0}; char dimname[NC_MAX_NAME + 1]; @@ -3350,24 +3541,32 @@ output netCDF files */ void SW_NC_write_output( SW_OUT_DOM *OutDom, - RealD *p_OUT[][SW_OUTNPERIODS], - int numFilesPerKey, + double *p_OUT[][SW_OUTNPERIODS], + unsigned int numFilesPerKey, char **ncOutFileNames[][SW_OUTNPERIODS], - size_t ncSuid[], + const size_t ncSuid[], const char *domType, LOG_INFO *LogInfo ) { int key; OutPeriod pd; - RealD *p_OUTValPtr = NULL; - int fileNum, currFileID = 0, varNum, varID = -1; + double *p_OUTValPtr = NULL; + unsigned int fileNum; + int currFileID = 0; + int varNum; + int varID = -1; - char *fileName, *varName; + char *fileName; + char *varName; size_t count[MAX_NUM_DIMS] = {0}; size_t start[MAX_NUM_DIMS] = {0}; - size_t pOUTIndex, startTime, timeSize = 0, countTotal = 0; - int vertSize, pftSize; + size_t pOUTIndex; + size_t startTime; + size_t timeSize = 0; + size_t countTotal = 0; + int vertSize; + int pftSize; start[0] = ncSuid[0]; start[1] = ncSuid[1]; @@ -3553,32 +3752,40 @@ void SW_NC_create_output_files( Bool hasConsistentSoilLayerDepths, double lyrDepths[], int strideOutYears, - int startYr, - int endYr, + unsigned int startYr, + unsigned int endYr, int baseCalendarYear, - int *numFilesPerKey, + unsigned int *numFilesPerKey, char **ncOutFileNames[][SW_OUTNPERIODS], LOG_INFO *LogInfo ) { - int key, ip; + int key; + int ip; + int resSNP; OutPeriod pd; - int rangeStart, rangeEnd, fileNum; + unsigned int rangeStart; + unsigned int rangeEnd; + unsigned int fileNum; - int numYears = endYr - startYr + 1, yearOffset; + unsigned int numYears = endYr - startYr + 1; + unsigned int yearOffset; char fileNameBuf[MAX_FILENAMESIZE]; char yearBuff[10]; // 10 - hold up to YYYY-YYYY - int timeSize = 0, baseTime = 0; + unsigned int timeSize = 0; + unsigned int baseTime = 0; double startTime[SW_OUTNPERIODS]; char periodSuffix[10]; char *yearFormat; - *numFilesPerKey = (strideOutYears == -1) ? - 1 : - (int) ceil((double) numYears / strideOutYears); + *numFilesPerKey = + (strideOutYears == -1) ? + 1 : + (unsigned int) ceil((double) numYears / strideOutYears); - yearOffset = (strideOutYears == -1) ? numYears : strideOutYears; + yearOffset = + (strideOutYears == -1) ? numYears : (unsigned int) strideOutYears; yearFormat = (strideOutYears == 1) ? (char *) "%d" : (char *) "%d-%d"; @@ -3595,7 +3802,9 @@ void SW_NC_create_output_files( baseTime = times[pd]; rangeStart = startYr; - snprintf(periodSuffix, 9, "%s", pd2longstr[pd]); + (void) sw_memccpy( + periodSuffix, (char *) pd2longstr[pd], '\0', 9 + ); Str_ToLower(periodSuffix, periodSuffix); SW_NC_alloc_files( @@ -3611,12 +3820,12 @@ void SW_NC_create_output_files( rangeEnd = rangeStart + yearOffset; } - snprintf( + (void) snprintf( yearBuff, 10, yearFormat, rangeStart, rangeEnd - 1 ); - snprintf( + resSNP = snprintf( fileNameBuf, - MAX_FILENAMESIZE, + sizeof fileNameBuf, "%s%s_%s_%s.nc", output_prefix, key2str[key], @@ -3624,6 +3833,17 @@ void SW_NC_create_output_files( periodSuffix ); + if (resSNP < 0 || + (unsigned) resSNP >= (sizeof fileNameBuf)) { + LogError( + LogInfo, + LOGERROR, + "nc-output file name '%s' is too long.", + fileNameBuf + ); + return; // Exit function prematurely due to error + } + ncOutFileNames[key][pd][fileNum] = Str_Dup(fileNameBuf, LogInfo); if (LogInfo->stopRun) { @@ -3777,12 +3997,15 @@ void SW_NC_check( Bool geoIsPrimCRS = SW_Domain->netCDFInfo.primary_crs_is_geographic; char strAttVal[LARGE_VALUE]; double doubleAttVal; - const char *geoCRS = "crs_geogsc", *projCRS = "crs_projsc"; + const char *geoCRS = "crs_geogsc"; + const char *projCRS = "crs_projsc"; Bool geoCRSExists = varExists(ncFileID, geoCRS); Bool projCRSExists = varExists(ncFileID, projCRS); const char *impliedDomType = (dimExists("site", ncFileID)) ? "s" : "xy"; Bool dimMismatch = swFALSE; - size_t latDimVal = 0, lonDimVal = 0, SDimVal = 0; + size_t latDimVal = 0; + size_t lonDimVal = 0; + size_t SDimVal = 0; const char *strAttsToComp[] = {"long_name", "grid_mapping_name", "crs_wkt"}; const char *doubleAttsToComp[] = { @@ -3833,7 +4056,9 @@ void SW_NC_check( crs_projsc->false_northing, }; - const int numNormAtts = 3, numProjStrAtts = 2, numProjDoubleAtts = 4; + const int numNormAtts = 3; + const int numProjStrAtts = 2; + const int numProjDoubleAtts = 4; double projStdParallel[2]; // Compare to standard_parallel is projected CRS int attNum; @@ -4115,10 +4340,17 @@ void SW_NC_create_domain_template( SW_NETCDF *SW_netCDF = &SW_Domain->netCDFInfo; int *domFileID = &SW_Domain->netCDFInfo.ncFileIDs[vNCdom]; - int sDimID = 0, YDimID = 0, XDimID = 0; + int sDimID = 0; + int YDimID = 0; + int XDimID = 0; int domDims[2]; // Either [YDimID, XDimID] or [sDimID, 0] - int nDomainDims, domVarID = 0, YVarID = 0, XVarID = 0, sVarID = 0; - int YBndsID = 0, XBndsID = 0; + int nDomainDims; + int domVarID = 0; + int YVarID = 0; + int XVarID = 0; + int sVarID = 0; + int YBndsID = 0; + int XBndsID = 0; if (isnull(fileName)) { fileName = (char *) DOMAIN_TEMP; @@ -4453,7 +4685,8 @@ void SW_NC_set_progress( ) { const signed char mark = (isFailure) ? PRGRSS_FAIL : PRGRSS_DONE; - size_t count1D[] = {1}, count2D[] = {1, 1}; + size_t count1D[] = {1}; + size_t count2D[] = {1, 1}; size_t *count = (strcmp(domType, "s") == 0) ? count1D : count2D; fill_netCDF_var_byte(progFileID, progVarID, &mark, ncSUID, count, LogInfo); @@ -4496,18 +4729,20 @@ void SW_NC_read_inputs( SW_RUN *sw, SW_DOMAIN *SW_Domain, size_t ncSUID[], LOG_INFO *LogInfo ) { - int file, varNum; + int file; + int varNum; Bool domTypeS = (Bool) (Str_CompareI(SW_Domain->DomainType, (char *) "s") == 0); const int numInFilesNC = 1; const int numDomVals = 2; const int numVals[] = {numDomVals}; const int ncFileIDs[] = {SW_Domain->netCDFInfo.ncFileIDs[vNCdom]}; - const char *domLatVar = "lat", *domLonVar = "lon"; + const char *domLatVar = "lat"; + const char *domLonVar = "lon"; const char *varNames[][2] = {{domLatVar, domLonVar}}; int ncIndex; - RealD *values[][2] = {{&sw->Model.latitude, &sw->Model.longitude}}; + double *values[][2] = {{&sw->Model.latitude, &sw->Model.longitude}}; /* Gather all values being requested within the array "values" @@ -4578,17 +4813,31 @@ void SW_NC_read(SW_NETCDF *SW_netCDF, PATH_INFO *PathInfo, LOG_INFO *LogInfo) { Bool hasKeys[NUM_NC_IN_KEYS] = {swFALSE, swFALSE}; FILE *f; - char inbuf[MAX_FILENAMESIZE], *MyFileName; + char inbuf[MAX_FILENAMESIZE]; + char *MyFileName; char key[15]; // 15 - Max key size - char varName[MAX_FILENAMESIZE], path[MAX_FILENAMESIZE]; + char varName[MAX_FILENAMESIZE]; + char path[MAX_FILENAMESIZE]; int keyID; + int scanRes; MyFileName = PathInfo->InFiles[eNCIn]; f = OpenFile(MyFileName, "r", LogInfo); // Get domain file name while (GetALine(f, inbuf, MAX_FILENAMESIZE)) { - sscanf(inbuf, "%14s %s %s", key, varName, path); + scanRes = sscanf(inbuf, "%14s %s %s", key, varName, path); + + if (scanRes < 3) { + LogError( + LogInfo, + LOGERROR, + "Not enough values found in %s (should be key, variable " + "name, path to input).", + MyFileName + ); + goto closeFile; + } keyID = key_to_id(key, possibleKeys, NUM_NC_IN_KEYS); set_hasKey( @@ -4616,18 +4865,18 @@ void SW_NC_read(SW_NETCDF *SW_netCDF, PATH_INFO *PathInfo, LOG_INFO *LogInfo) { } } - CloseFile(&f, LogInfo); - // Check if all required input was provided check_requiredKeys( hasKeys, requiredKeys, possibleKeys, NUM_NC_IN_KEYS, LogInfo ); if (LogInfo->stopRun) { - return; // Exit function prematurely due to error + goto closeFile; } // Read CRS and attributes for netCDFs nc_read_atts(SW_netCDF, PathInfo, LogInfo); + +closeFile: { CloseFile(&f, LogInfo); } } /** @@ -4661,28 +4910,42 @@ void SW_NC_read_out_vars( FILE *f; OutKey currOutKey; - char inbuf[MAX_FILENAMESIZE], *MyFileName; + char inbuf[MAX_FILENAMESIZE]; + char *MyFileName; char varKey[MAX_FILENAMESIZE + 1]; - int varNum = 0, lineno = 0; + int varNum = 0; + int lineno = 0; Bool estabFound = swFALSE; Bool used_OutKeys[SW_OUTNKEYS] = {swFALSE}; int varNumUnits; - int index, estVar; + int index; + int estVar; + int resSNP; char *copyStr = NULL; char input[NOUT_VAR_INPUTS][MAX_ATTVAL_SIZE] = {"\0"}; char establn[MAX_ATTVAL_SIZE] = {"\0"}; - int scanRes = 0, defToLocalInd = 0; + int scanRes = 0; + int defToLocalInd = 0; // in readLineFormat: 255 must be equal to MAX_ATTVAL_SIZE - 1 const char *readLineFormat = "%13[^\t]\t%50[^\t]\t%50[^\t]\t%10[^\t]\t%4[^\t]\t%1[^\t]\t" "%255[^\t]\t%255[^\t]\t%255[^\t]\t%255[^\t]\t%255[^\t]\t%255[^\t]"; + int doOutputVal; // Column indices - const int keyInd = 0, SWVarNameInd = 1, SWTxtNameInd = 2, SWUnitsInd = 3, - dimInd = 4, doOutInd = 5, outVarNameInd = 6, longNameInd = 7, - commentInd = 8, outUnits = 9, cellMethodInd = 10, - usercommentInd = 11; + const int keyInd = 0; + const int SWVarNameInd = 1; + const int SWTxtNameInd = 2; + const int SWUnitsInd = 3; + const int dimInd = 4; + const int doOutInd = 5; + const int outVarNameInd = 6; + const int longNameInd = 7; + const int commentInd = 8; + const int outUnits = 9; + const int cellMethodInd = 10; + const int usercommentInd = 11; MyFileName = InFiles[eNCOutVars]; f = OpenFile(MyFileName, "r", LogInfo); @@ -4735,16 +4998,31 @@ void SW_NC_read_out_vars( // Check if the variable was requested to be output // Store attribute information for each variable (including names) - if (atoi(input[doOutInd])) { - snprintf( + doOutputVal = sw_strtoi(input[doOutInd], MyFileName, LogInfo); + if (LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + if (doOutputVal) { + resSNP = snprintf( varKey, - MAX_FILENAMESIZE + 1, + sizeof varKey, "%s__%s", input[keyInd], input[SWVarNameInd] ); + if (resSNP < 0 || (unsigned) resSNP >= (sizeof varKey)) { + LogError( + LogInfo, + LOGERROR, + "nc-output variable name '%s' is too long.", + varKey + ); + return; // Exit function prematurely due to error + } + get_2d_output_key(varKey, &currOutKey, &varNum, OutDom->nvar_OUT); if (currOutKey == eSW_NoKey) { @@ -4860,11 +5138,8 @@ void SW_NC_read_out_vars( break; case LONGNAME_INDEX: - snprintf( - establn, - MAX_ATTVAL_SIZE - 1, - copyStr, - parms[estVar]->sppname + (void) sw_memccpy( + establn, copyStr, '\0', MAX_ATTVAL_SIZE ); OutDom->outputVarInfo[currOutKey][estVar][index] = Str_Dup(establn, LogInfo); @@ -4932,11 +5207,13 @@ This function requires previous calls to @param[out] LogInfo Holds information on warnings and errors */ void SW_NC_create_units_converters(SW_OUT_DOM *OutDom, LOG_INFO *LogInfo) { - int varIndex, key; + int varIndex; + int key; #if defined(SWUDUNITS) ut_system *system; - ut_unit *unitFrom, *unitTo; + ut_unit *unitFrom; + ut_unit *unitTo; /* silence udunits2 error messages */ ut_set_error_message_handler(ut_ignore); @@ -5124,8 +5401,11 @@ netCDF file information @param[out] LogInfo Holds information on warnings and errors */ void SW_NC_open_dom_prog_files(SW_NETCDF *SW_netCDF, LOG_INFO *LogInfo) { - int fileNum, openType = NC_WRITE, *fileID; - char *fileName, *domFile = SW_netCDF->InFilesNC[vNCdom]; + int fileNum; + int openType = NC_WRITE; + int *fileID; + char *fileName; + char *domFile = SW_netCDF->InFilesNC[vNCdom]; char *progFile = SW_netCDF->InFilesNC[vNCprog]; Bool progFileDomain = (Bool) (strcmp(domFile, progFile) == 0); @@ -5196,7 +5476,8 @@ void SW_NC_close_files(SW_NETCDF *SW_netCDF) { @param[out] LogInfo Holds information on warnings and errors */ void SW_NC_deepCopy(SW_NETCDF *source, SW_NETCDF *dest, LOG_INFO *LogInfo) { - int index, numIndivCopy = 5; + int index; + int numIndivCopy = 5; char *srcStrs[] = { source->title, @@ -5297,12 +5578,12 @@ void SW_NC_dealloc_outputkey_var_info(SW_OUT_DOM *OutDom, IntUS k) { } } - free(OutDom->outputVarInfo[k][varNum]); + free((void *) OutDom->outputVarInfo[k][varNum]); OutDom->outputVarInfo[k][varNum] = NULL; } } - free(OutDom->outputVarInfo[k]); + free((void *) OutDom->outputVarInfo[k]); OutDom->outputVarInfo[k] = NULL; } @@ -5314,7 +5595,7 @@ void SW_NC_dealloc_outputkey_var_info(SW_OUT_DOM *OutDom, IntUS k) { } } - free(OutDom->units_sw[k]); + free((void *) OutDom->units_sw[k]); OutDom->units_sw[k] = NULL; } @@ -5330,7 +5611,7 @@ void SW_NC_dealloc_outputkey_var_info(SW_OUT_DOM *OutDom, IntUS k) { } } - free(OutDom->uconv[k]); + free((void *) OutDom->uconv[k]); OutDom->uconv[k] = NULL; } @@ -5348,9 +5629,11 @@ functions to write to/create @param[in] numFiles Number of file names to store/allocate memory for @param[out] LogInfo Holds information on warnings and errors */ -void SW_NC_alloc_files(char ***ncOutFiles, int numFiles, LOG_INFO *LogInfo) { +void SW_NC_alloc_files( + char ***ncOutFiles, unsigned int numFiles, LOG_INFO *LogInfo +) { - int varNum; + unsigned int varNum; *ncOutFiles = (char **) Mem_Malloc( numFiles * sizeof(char *), "SW_NC_create_output_files()", LogInfo diff --git a/src/Times.c b/src/Times.c index 4fff2eeb4..a146c0e67 100644 --- a/src/Times.c +++ b/src/Times.c @@ -32,6 +32,7 @@ /* --------------------------------------------------- */ #include "include/Times.h" // for Jan, Dec, Feb, NoMonth, NoDay +#include "include/filefuncs.h" // for sw_message #include "include/generic.h" // for Bool, GE, final_running_sd, get_... #include "include/SW_datastructs.h" // for SW_WALLTIME, LOG_INFO #include "include/SW_Defines.h" // for TimeInt, WallTimeSpec, MAX_DAYS @@ -123,7 +124,7 @@ TimeInt Time_get_lastdoy_y(TimeInt year) { @return Month (base0) [Jan-Dec = 0-11]. */ -TimeInt doy2month(const TimeInt doy, TimeInt cum_monthdays[]) { +TimeInt doy2month(const TimeInt doy, const TimeInt cum_monthdays[]) { TimeInt mon; for (mon = Jan; mon < Dec && doy > cum_monthdays[mon]; mon++) @@ -141,7 +142,7 @@ TimeInt doy2month(const TimeInt doy, TimeInt cum_monthdays[]) { @return Day of the month [1-31]. */ TimeInt doy2mday( - const TimeInt doy, TimeInt cum_monthdays[], TimeInt days_in_month[] + const TimeInt doy, TimeInt cum_monthdays[], const TimeInt days_in_month[] ) { TimeInt new_doy0 = doy2month(doy, cum_monthdays) - 1; @@ -168,7 +169,13 @@ Useful for formatting user inputs. */ TimeInt yearto4digit(TimeInt yr) { // called by SW_MDL_read(), SW_WTH_read(), SW_SWC_read() - return (TimeInt) ((yr > 100) ? yr : (yr < 50) ? 2000 + yr : 1900 + yr); + TimeInt year = yr; + + if (yr <= 100) { + year = (yr < 50) ? 2000 + yr : 1900 + yr; + } + + return year; } /** @@ -207,14 +214,20 @@ index for "day of year" (doy) is used, i.e., the value on the first day of year (`doy = 0`) is located in `dailyValues[0]`. */ void interpolate_monthlyValues( - double monthlyValues[], + const double monthlyValues[], Bool interpAsBase1, TimeInt cum_monthdays[], TimeInt days_in_month[], double dailyValues[] ) { - unsigned int doy, mday, month, month2 = NoMonth, nmdays; - unsigned int startdoy = 1, endDay = MAX_DAYS, doyOffset = 0; + unsigned int doy; + unsigned int mday; + unsigned int month; + unsigned int month2 = NoMonth; + unsigned int nmdays; + unsigned int startdoy = 1; + unsigned int endDay = MAX_DAYS; + unsigned int doyOffset = 0; double sign = 1.; // Check if we are interpolating values as base1 @@ -291,7 +304,7 @@ double diff_walltime(WallTimeSpec start, Bool ok_start) { #if SW_TIMESPEC == 1 /* C11 or later */ d = difftime(end.tv_sec, start.tv_sec) + - (end.tv_nsec - start.tv_nsec) / 1000000000.; + (double) (end.tv_nsec - start.tv_nsec) / 1.e9; #else d = difftime(end, start); @@ -363,40 +376,59 @@ Time is not reported at all if quiet mode and `logfile` is `NULL`. void SW_WT_ReportTime(SW_WALLTIME wt, LOG_INFO *LogInfo) { double total_time = 0; unsigned long nSims = wt.nTimedRuns + wt.nUntimedRuns; + int fprintRes = 0; - FILE *logfp = (Bool) LogInfo->QuietMode ? LogInfo->logfp : stdout; + FILE *logfp = LogInfo->QuietMode ? LogInfo->logfp : stdout; if (isnull(logfp)) { return; } - fprintf(logfp, "Time report\n"); + fprintRes = fprintf(logfp, "Time report\n"); + if (fprintRes < 0) { + goto wrapUpErrMsg; + } // negative if failed total_time = diff_walltime(wt.timeStart, wt.has_walltime); if (GE(total_time, 0.)) { - fprintf(logfp, " * Total wall time: %.2f [seconds]\n", total_time); + fprintRes = fprintf( + logfp, " * Total wall time: %.2f [seconds]\n", total_time + ); } else { - fprintf(logfp, " * Wall time failed.\n"); + fprintRes = fprintf(logfp, " * Wall time failed.\n"); + } + if (fprintRes < 0) { + goto wrapUpErrMsg; } if (nSims > 1) { - fprintf(logfp, " * Number of simulation runs: %lu", nSims); + fprintRes = + fprintf(logfp, " * Number of simulation runs: %lu", nSims); + if (fprintRes < 0) { + goto wrapUpErrMsg; + } if (wt.nUntimedRuns > 0) { - fprintf( + fprintRes = fprintf( logfp, " total (%lu timed | %lu untimed)", wt.nTimedRuns, wt.nUntimedRuns ); + if (fprintRes < 0) { + goto wrapUpErrMsg; + } } - fprintf(logfp, "\n"); + fprintRes = fprintf(logfp, "\n"); + if (fprintRes < 0) { + goto wrapUpErrMsg; + } if (wt.nTimedRuns > 0) { - fprintf( + fprintRes = fprintf( logfp, " * Variation among simulation runs: " "%.3f mean (%.3f SD, %.3f-%.3f min-max) [seconds]\n", @@ -405,17 +437,26 @@ void SW_WT_ReportTime(SW_WALLTIME wt, LOG_INFO *LogInfo) { wt.timeMin, wt.timeMax ); + if (fprintRes < 0) { + goto wrapUpErrMsg; + } } } if (GT(total_time, 0.) && GE(wt.timeSimSet, 0.)) { - fprintf( + fprintRes = fprintf( logfp, " * Wall time for simulation set: %.2f %% [percent of total " "wall time]\n", 100. * wt.timeSimSet / total_time ); } + +wrapUpErrMsg: { + if (fprintRes < 0) { + sw_message("Failed to write whole time report."); + } +} } /** @@ -426,5 +467,7 @@ void SW_WT_ReportTime(SW_WALLTIME wt, LOG_INFO *LogInfo) { */ void timeStringISO8601(char *timeString, int stringLength) { time_t t = time(NULL); - strftime(timeString, stringLength, "%FT%TZ", gmtime(&t)); + if (strftime(timeString, stringLength, "%FT%TZ", gmtime(&t)) == 0) { + timeString[0] = '\0'; + } } diff --git a/src/filefuncs.c b/src/filefuncs.c index ea7450093..8b20838e7 100644 --- a/src/filefuncs.c +++ b/src/filefuncs.c @@ -15,12 +15,15 @@ #include "include/SW_Defines.h" // for MAX_LOG_SIZE, KEY_NOT_FOUND, MAX... #include "include/Times.h" // for timeStringISO8601 #include // for assert +#include // for isspace #include // for dirent, closedir, DIR, opendir, re... -#include // for errno, EACCES +#include // for errno, ERANGE +#include // for LONG_MIN, LONG_MAX, INT_MIN, INT_MAX +#include // for HUGE_VAL, HUGE_VALF #include // for va_end, va_start #include // for NULL, fclose, FILE, fopen, EOF -#include // for free -#include // for strlen, strrchr, strcpy, strchr +#include // for free, strtod, strtof, strtol +#include // for strlen, strrchr, memccpy, strchr #include // for stat, mkdir, S_ISDIR, S_ISREG #include // for chdir @@ -47,7 +50,7 @@ static void freeGetfilesEarly(char **flist, int nfound, DIR *dir, char *fname) { } } - free(flist); + free((void *) flist); flist = NULL; } @@ -67,13 +70,20 @@ static char **getfiles(const char *fspec, int *nfound, LOG_INFO *LogInfo) { * nfound is the number of files found, also, num elements in flist */ - char **flist = NULL, *fname, *fn1, *fn2, *p2; + char **flist = NULL; + char *fname; + char *fn1; + char *fn2; + char *p2; char dname[FILENAME_MAX]; - int startIndex = 0, strLen = 0; // For `sw_strtok()` + size_t startIndex = 0; + size_t strLen = 0; // For `sw_strtok()` - int len1, len2; - Bool match, alloc = swFALSE; + size_t len1; + size_t len2; + Bool match; + Bool alloc = swFALSE; DIR *dir; struct dirent *ent; @@ -97,8 +107,9 @@ static char **getfiles(const char *fspec, int *nfound, LOG_INFO *LogInfo) { len2 = (fn2) ? strlen(fn2) : 0; (*nfound) = 0; + dir = opendir(dname); - if ((dir = opendir(dname)) == NULL) { + if (isnull(dir)) { free(fname); return NULL; } @@ -117,7 +128,7 @@ static char **getfiles(const char *fspec, int *nfound, LOG_INFO *LogInfo) { (*nfound)++; if (alloc) { flist = (char **) Mem_ReAlloc( - flist, sizeof(char *) * (*nfound), LogInfo + (void *) flist, sizeof(char *) * (*nfound), LogInfo ); if (LogInfo->stopRun) { @@ -176,53 +187,61 @@ void LogError(LOG_INFO *LogInfo, const int mode, const char *fmt, ...) { int nextWarn = LogInfo->numWarnings; va_list args; int expectedWriteSize; + char *writePtr = msgType; va_start(args, fmt); if (LOGWARN & mode) { - strcpy(msgType, "WARNING: "); + (void) sw_memccpy(writePtr, "WARNING: ", '\0', MAX_LOG_SIZE); } else if (LOGERROR & mode) { - strcpy(msgType, "ERROR: "); + (void) sw_memccpy(writePtr, "ERROR: ", '\0', MAX_LOG_SIZE); } expectedWriteSize = snprintf(outfmt, MAX_LOG_SIZE, "%s%s\n", msgType, fmt); if (expectedWriteSize > MAX_LOG_SIZE) { // Silence gcc (>= 7.1) compiler flag `-Wformat-truncation=`, i.e., // handle output truncation - fprintf(stderr, "Programmer: message exceeds the maximum size.\n"); + (void + ) fprintf(stderr, "Programmer: message exceeds the maximum size.\n"); #ifdef SWDEBUG exit(EXIT_FAILURE); #endif } + // NOLINTNEXTLINE(clang-analyzer-valist.Uninitialized) expectedWriteSize = vsnprintf(buf, MAX_LOG_SIZE, outfmt, args); #ifdef SWDEBUG if (expectedWriteSize > MAX_LOG_SIZE) { - fprintf( + (void) fprintf( stderr, "Programmer: Injecting arguments to final message buffer " "makes it exceed the maximum size.\n" ); exit(EXIT_FAILURE); } +#else + (void) expectedWriteSize; /* Silence clang-tidy + clang-analyzer-deadcode.DeadStores */ #endif if (LOGWARN & mode) { if (nextWarn < MAX_MSGS) { - strcpy(LogInfo->warningMsgs[nextWarn], buf); + (void) sw_memccpy( + LogInfo->warningMsgs[nextWarn], buf, '\0', MAX_LOG_SIZE + ); } LogInfo->numWarnings++; } else if (LOGERROR & mode) { #ifdef STEPWAT - fprintf(stderr, "%s", buf); + (void) fprintf(stderr, "%s", buf); // Consider updating STEPWAT2: instead of exiting/crashing, do catch // errors, recoil, and use `sw_write_warnings(); sw_fail_on_error()` // as SOILWAT2 >= 7.2.0 exit(EXIT_FAILURE); #else - strcpy(LogInfo->errorMsg, buf); + (void) sw_memccpy(LogInfo->errorMsg, buf, '\0', MAX_LOG_SIZE); LogInfo->stopRun = swTRUE; #endif } @@ -242,6 +261,202 @@ void sw_message(const char *msg) { sw_printf("SOILWAT2 (%s) %s\n", timeString, msg); } +/** +@brief Convert string to unsigned long integer with error handling + +This function implements cert-err34-c +"Detect errors when converting a string to a number". + +@param[in] str Pointer to string to be converted. +@param[in] errMsg Pointer to string included in error message. +@param[out] LogInfo Holds information on warnings and errors +*/ +unsigned long int sw_strtoul( + const char *str, const char *errMsg, LOG_INFO *LogInfo +) { + unsigned long int resul = ULONG_MAX; + char *endStr; + + errno = 0; + + resul = strtoul(str, &endStr, 10); + + if (endStr == str || '\0' != *endStr) { + LogError( + LogInfo, + LOGERROR, + "%s: converting '%s' to unsigned long integer failed.", + errMsg, + str + ); + + } else if (ULONG_MAX == resul && ERANGE == errno) { + LogError( + LogInfo, + LOGERROR, + "%s: '%s' out of range of type unsigned long integer.", + errMsg, + str + ); + } + + return resul; +} + +/** +@brief Convert string to long integer with error handling + +This function implements cert-err34-c +"Detect errors when converting a string to a number". + +@param[in] str Pointer to string to be converted. +@param[in] errMsg Pointer to string included in error message. +@param[out] LogInfo Holds information on warnings and errors +*/ +long int sw_strtol(const char *str, const char *errMsg, LOG_INFO *LogInfo) { + long int resl = LONG_MIN; + char *endStr; + + errno = 0; + + resl = strtol(str, &endStr, 10); + + if (endStr == str || '\0' != *endStr) { + LogError( + LogInfo, + LOGERROR, + "%s: converting '%s' to long integer failed.", + errMsg, + str + ); + + } else if ((LONG_MIN == resl || LONG_MAX == resl) && ERANGE == errno) { + LogError( + LogInfo, + LOGERROR, + "%s: '%s' out of range of type long integer.", + errMsg, + str + ); + } + + return resl; +} + +/** +@brief Convert string to integer with error handling + +This function implements cert-err34-c +"Detect errors when converting a string to a number". + +@param[in] str Pointer to string to be converted. +@param[in] errMsg Pointer to string included in error message. +@param[out] LogInfo Holds information on warnings and errors +*/ +int sw_strtoi(const char *str, const char *errMsg, LOG_INFO *LogInfo) { + long int resl; + int resi = INT_MIN; + + resl = sw_strtol(str, errMsg, LogInfo); + + if (!LogInfo->stopRun) { + if (resl > INT_MAX || resl < INT_MIN) { + LogError( + LogInfo, + LOGERROR, + "%s: '%s' out of range of type integer.", + errMsg, + str + ); + + } else { + resi = (int) resl; + } + } + + return resi; +} + +/** +@brief Convert string to double with error handling + +This function implements cert-err34-c +"Detect errors when converting a string to a number". + +@param[in] str Pointer to string to be converted. +@param[in] errMsg Pointer to string included in error message. +@param[out] LogInfo Holds information on warnings and errors +*/ +double sw_strtod(const char *str, const char *errMsg, LOG_INFO *LogInfo) { + double resd = HUGE_VAL; + char *endStr; + + errno = 0; + + resd = strtod(str, &endStr); + + if (endStr == str || '\0' != *endStr) { + LogError( + LogInfo, + LOGERROR, + "%s: converting '%s' to double failed.", + errMsg, + str + ); + + } else if (HUGE_VAL == resd && ERANGE == errno) { + LogError( + LogInfo, + LOGERROR, + "%s: '%s' out of range of type double.", + errMsg, + str + ); + } + + return resd; +} + +/** +@brief Convert string to float with error handling + +This function implements cert-err34-c +"Detect errors when converting a string to a number". + +@param[in] str Pointer to string to be converted. +@param[in] errMsg Pointer to string included in error message. +@param[out] LogInfo Holds information on warnings and errors +*/ +float sw_strtof(const char *str, const char *errMsg, LOG_INFO *LogInfo) { + float resf = HUGE_VALF; + char *endStr; + + errno = 0; + + resf = strtof(str, &endStr); + + if (endStr == str || '\0' != *endStr) { + LogError( + LogInfo, + LOGERROR, + "%s: converting '%s' to float failed.", + errMsg, + str + ); + + } else if (HUGE_VALF == resf && ERANGE == errno) { + LogError( + LogInfo, + LOGERROR, + "%s: '%s' out of range of type float.", + errMsg, + str + ); + } + + return resf; +} + /**************************************************************/ Bool GetALine(FILE *f, char buf[], int numChars) { /* Read a line of possibly commented input from the file *f. @@ -251,7 +466,8 @@ Bool GetALine(FILE *f, char buf[], int numChars) { char *p; Bool not_eof = swFALSE; while (!isnull(fgets(buf, numChars, f))) { - if (!isnull(p = strchr(buf, (int) '\n'))) { + p = strchr(buf, '\n'); + if (!isnull(p)) { *p = '\0'; } @@ -270,13 +486,16 @@ void DirName(const char *p, char *outString) { * Be sure to copy the return value to a more stable buffer * before moving on. */ - char *c; - int l; - char sep1 = '/', sep2 = '\\'; + const char *c; + long int l; + char sep1 = '/'; + char sep2 = '\\'; *outString = '\0'; - if (!(c = (char *) strrchr(p, (int) sep1))) { - c = (char *) strrchr(p, (int) sep2); + c = strrchr(p, (int) sep1); + + if (!c) { + c = strrchr(p, (int) sep2); } if (c) { @@ -291,14 +510,16 @@ const char *BaseName(const char *p) { /* return a pointer to the terminal element (file) of a path. */ /* Doesn't modify the string, but you'll probably want to * copy the result to a stable buffer. */ - char *c; - char sep1 = '/', sep2 = '\\'; + const char *c; + char sep1 = '/'; + char sep2 = '\\'; - if (!(c = (char *) strrchr(p, (int) sep1))) { - c = (char *) strrchr(p, (int) sep2); + c = strrchr(p, (int) sep1); + if (!c) { + c = strrchr(p, (int) sep2); } - return ((c != NULL) ? c + 1 : p); + return (isnull(c) ? p : c + 1); } /**************************************************************/ @@ -306,10 +527,8 @@ FILE *OpenFile(const char *name, const char *mode, LOG_INFO *LogInfo) { FILE *fp; fp = fopen(name, mode); if (isnull(fp)) { - LogError( - LogInfo, LOGERROR, "Cannot open file %s: %s", name, strerror(errno) - ); - return NULL; // Exit function prematurely due to error + // Report error if file couldn't be opened + LogError(LogInfo, LOGERROR, "Cannot open file '%s'", name); } return (fp); } @@ -325,13 +544,14 @@ void CloseFile(FILE **f, LOG_INFO *LogInfo) { */ if (*f == NULL) { LogError( - LogInfo, - LOGWARN, - "Tried to close file that doesn't exist or isn't open!" + LogInfo, LOGWARN, "CloseFile: file doesn't exist or isn't open!" ); return; } - fclose(*f); + + if (fclose(*f) == EOF) { + LogError(LogInfo, LOGERROR, "CloseFile: Could not close file."); + } *f = NULL; } @@ -387,14 +607,14 @@ Bool ChDir(const char *dname) { #define mkdir(d, m) mkdir(d, m) #endif -Bool MkDir(const char *dname, LOG_INFO *LogInfo) { +// Errors are reported via LogInfo +void MkDir(const char *dname, LOG_INFO *LogInfo) { /* make a path with 'mkdir -p' -like behavior. provides an * interface for portability problems. * RELATIVE PATH ONLY solves problems like "C:\etc" and null * first element in absolute path. * if you need to make an absolute path, use ChDir() first. * if you care about mode of new dir, use mkdir(), not MkDir() - * if MkDir returns FALSE, check errno. * * Notes: * - portability issues seem to be quite problematic, at least @@ -402,50 +622,78 @@ Bool MkDir(const char *dname, LOG_INFO *LogInfo) { * error code is EACCES, so if something else happens (and it * well might in unix), more tests have to be included, perhaps * with macros that test the compiler/platform. - * - we're borrowing errstr to build the path to facilitate the + * - we're borrowing buffer to build the path to facilitate the * -p behavior. */ - int r, i, n; - Bool result = swTRUE; + int i; + int n; char *a[256] = {0}; /* points to each path element for mkdir -p behavior */ char *c; /* duplicate of dname so we don't change it */ const char *delim = "\\/"; /* path separators */ - char errstr[MAX_ERROR]; + char buffer[MAX_ERROR]; + char *writePtr = buffer; + char *resPtr = NULL; - int startIndex = 0, strLen = 0; // For `sw_strtok()` + size_t startIndex = 0; + size_t strLen = 0; // For `sw_strtok()` + size_t writeSize = 256; if (isnull(dname)) { - return swFALSE; + return; } c = Str_Dup(dname, LogInfo); if (LogInfo->stopRun) { - return swFALSE; // Exit function prematurely due to error + return; // Exit function prematurely due to error } /* parse path */ n = 0; - while (NULL != (a[n++] = sw_strtok(c, &startIndex, &strLen, delim))) - ; + while (NULL != (a[n] = sw_strtok(c, &startIndex, &strLen, delim)) && n < 256 + ) { + n++; + } - n--; - errstr[0] = '\0'; + buffer[0] = '\0'; for (i = 0; i < n; i++) { - strcat(errstr, a[i]); - if (!DirExists(errstr)) { - if (0 != (r = mkdir(errstr, 0777))) { - if (errno == EACCES) { - result = swFALSE; - break; - } + if (!isnull(resPtr) || i == 0) { + resPtr = (char *) sw_memccpy(writePtr, a[i], '\0', writeSize); + writeSize -= (resPtr - buffer - 1); + writePtr = resPtr - 1; + } + + if (!DirExists(buffer) || isnull(resPtr)) { + if (0 != mkdir(buffer, 0777)) { + // directory failed to create -> report error + LogError( + LogInfo, LOGERROR, "Failed to create directory '%s'", buffer + ); + goto freeMem; // Exit function prematurely due to error + } else if (isnull(resPtr)) { + /* Directory was created but not by the expected name */ + LogError( + LogInfo, + LOGWARN, + "Could not create the desired directory. The path created " + "instead is '%s'.", + buffer + ); + + /* No longer attempt to concatenate the directory */ + goto freeMem; } } - strcat(errstr, "/"); + + if (!isnull(resPtr)) { + resPtr = (char *) sw_memccpy(writePtr, "/", '\0', writeSize); + writePtr = resPtr - 1; + writeSize--; + } } +freeMem: free(c); - return result; } #undef mkdir @@ -461,42 +709,45 @@ Bool RemoveFiles(const char *fspec, LOG_INFO *LogInfo) { * eg: /here/now/fi*les, /here/now/files* * or /here/now/files * Returns TRUE if all files removed, FALSE otherwise. - * Check errno if return is FALSE. */ - char **flist, fname[FILENAME_MAX]; - int i, nfiles, dlen, result = swTRUE; + char **flist; + char fname[FILENAME_MAX]; + char *resPtr = NULL; + int i; + int nfiles; + int result = swTRUE; + size_t dlen; + size_t writeSize = FILENAME_MAX; if (fspec == NULL) { return swTRUE; } - if ((flist = getfiles(fspec, &nfiles, LogInfo))) { + flist = getfiles(fspec, &nfiles, LogInfo); + + if (!isnull(flist)) { DirName(fspec, fname); // Transfer `fspec` into `fname` dlen = strlen(fname); for (i = 0; i < nfiles; i++) { - strcpy(fname + dlen, flist[i]); + resPtr = + (char *) sw_memccpy(fname + dlen, flist[i], '\0', writeSize); + writeSize -= (resPtr - (fname + dlen) - 1); if (0 != remove(fname)) { result = swFALSE; break; } } - } - if (!isnull(flist)) { + for (i = 0; i < nfiles; i++) { if (!isnull(flist[i])) { free(flist[i]); } } - free(flist); + free((void *) flist); } - if (LogInfo->stopRun) { - return swFALSE; - } - - - return (Bool) result; + return (Bool) (result && !LogInfo->stopRun); } /** @@ -511,7 +762,8 @@ Bool RemoveFiles(const char *fspec, LOG_INFO *LogInfo) { Bool CopyFile(const char *from, const char *to, LOG_INFO *LogInfo) { char buffer[4096]; // or any other constant that is a multiple of 512 size_t n; - FILE *ffrom, *fto; + FILE *ffrom; + FILE *fto; ffrom = fopen(from, "r"); if (ffrom == NULL) { @@ -526,7 +778,6 @@ Bool CopyFile(const char *from, const char *to, LOG_INFO *LogInfo) { fto = fopen(to, "w"); if (fto == NULL) { - fclose(ffrom); LogError( LogInfo, LOGERROR, @@ -541,8 +792,8 @@ Bool CopyFile(const char *from, const char *to, LOG_INFO *LogInfo) { LogError( LogInfo, LOGERROR, "CopyFile: error while copying to %s.\n", to ); - fclose(ffrom); - fclose(fto); + (void) fclose(ffrom); + (void) fclose(fto); return swFALSE; // Exit function prematurely due to error } } @@ -551,8 +802,8 @@ Bool CopyFile(const char *from, const char *to, LOG_INFO *LogInfo) { LogError( LogInfo, LOGERROR, "CopyFile: error reading source file %s.\n", from ); - fclose(ffrom); - fclose(fto); + (void) fclose(ffrom); + (void) fclose(fto); return swFALSE; // Exit function prematurely due to error } @@ -632,7 +883,7 @@ void set_hasKey( @param[out] LogInfo Holds information on warnings and errors */ void check_requiredKeys( - Bool *hasKeys, + const Bool *hasKeys, const Bool *requiredKeys, const char **possibleKeys, int numKeys, diff --git a/src/generic.c b/src/generic.c index 17c58a398..0fa050d5d 100644 --- a/src/generic.c +++ b/src/generic.c @@ -29,9 +29,9 @@ static void uncomment_cstyle(char *p) { cwb - 9/11/01 -------------------------------------------*/ - char *e; /* end of comment */ + char *e = strchr(p + 2, '*'); /* end of comment */ - if ((e = strchr(p + 2, '*'))) { + if (e) { if (*(++e) == '/') { e++; while (*e) { @@ -56,7 +56,8 @@ char *Str_TrimLeft(char *s) { cwb - 18-Nov-02 -------------------------------------------*/ - char *q, *p; + char *q; + char *p; q = p = s; while (*q && isspace((int) *(q))) { q++; /* goto nonblank */ @@ -97,10 +98,11 @@ char *Str_TrimRight(char *s) { cwb - 9/11/01 moved this from Uncomment -------------------------------------------*/ - char *p = s + strlen(s); + char *p = s + strlen(s) - 1; - while ((--p) >= s && isspace((int) *p)) - ; + while (p >= s && isspace((int) *p)) { + p--; + } *(++p) = '\0'; return s; @@ -114,7 +116,8 @@ char *Str_ToUpper(char *s, char *r) { cwb - 10/5/01 -------------------------------------------*/ - char *p = s, *q = r; + char *p = s; + char *q = r; while (*p) { *(q++) = (char) toupper((int) (*(p++))); } @@ -130,7 +133,8 @@ char *Str_ToLower(char *s, char *r) { cwb - 10/5/01 -------------------------------------------*/ - char *p = s, *q = r; + char *p = s; + char *q = r; while (*p) { *(q++) = (char) tolower((int) (*(p++))); } @@ -144,7 +148,8 @@ int Str_CompareI(char *t, char *s) { * works like strcmp() except case-insensitive * cwb 4-Sep-03 */ - char *tChar = t, *sChar = s; + char *tChar = t; + char *sChar = s; // While t and s characters are not '\0' (null) // and the lower case character of t and s are the same @@ -165,9 +170,9 @@ int Str_CompareI(char *t, char *s) { This is a thread-safe replacement for strtok. */ char *sw_strtok( - char inputStr[], int *startIndex, int *strLen, const char *delim + char inputStr[], size_t *startIndex, size_t *strLen, const char *delim ) { - int index = *startIndex; + size_t index = *startIndex; char *newPtr = NULL; if (*startIndex == 0) { @@ -237,12 +242,16 @@ void UnComment(char *s) { cwb - 9/11/01 added c-style comment code and split out the different tasks. -------------------------------------------*/ - char *p; + char *p = strchr(s, '#'); - if ((p = strchr(s, '#'))) { + if (!isnull(p)) { *p = '\0'; - } else if ((p = strstr(s, "/*"))) { - uncomment_cstyle(p); + } else { + p = strstr(s, "/*"); + + if (!isnull(p)) { + uncomment_cstyle(p); + } } Str_TrimRight(s); @@ -308,7 +317,9 @@ void st_getBounds( if (LT(depth, bounds[0])) { *x2 = 0; return; - } else if (GT(depth, bounds[size - 1])) { + } + + if (GT(depth, bounds[size - 1])) { *x1 = size - 1; *x2 = -1; return; @@ -352,8 +363,12 @@ void st_getBounds( HISTORY: 05/29/2012 (DLM) initial coding **************************************************************************************************************************************/ -double lobfM(double xs[], double ys[], unsigned int n) { - double sumX, sumY, sumXY, sumX2, temp; +double lobfM(const double xs[], const double ys[], unsigned int n) { + double sumX; + double sumY; + double sumXY; + double sumX2; + double temp; unsigned int i; sumX = sumY = sumXY = sumX2 = 0.0; // init values to 0 @@ -381,7 +396,9 @@ double lobfM(double xs[], double ys[], unsigned int n) { 05/29/2012 (DLM) initial coding **************************************************************************************************************************************/ double lobfB(double xs[], double ys[], unsigned int n) { - double sumX, sumY, temp; + double sumX; + double sumY; + double temp; unsigned int i; sumX = sumY = 0.0; @@ -518,10 +535,12 @@ double final_running_sd(unsigned int n, double ssqr) { @note When a value is SW_MISSING, the function sees it as a value to skip and ignores it to not influence the mean. */ -double mean(double values[], int length) { +double mean(const double values[], unsigned int length) { - int index, finalLength = 0; - double total = 0.0, currentVal; + unsigned int index; + unsigned int finalLength = 0; + double total = 0.0; + double currentVal; for (index = 0; index < length; index++) { currentVal = values[index]; @@ -548,10 +567,13 @@ double mean(double values[], int length) { @note When a value is SW_MISSING, the function sees it as a value to skip and ignores it to not influence the standard deviation. */ -double standardDeviation(double inputArray[], int length) { +double standardDeviation(double inputArray[], unsigned int length) { - int index, finalLength = 0; - double arrayMean = mean(inputArray, length), total = 0.0, currentVal; + unsigned int index; + unsigned int finalLength = 0; + double arrayMean = mean(inputArray, length); + double total = 0.0; + double currentVal; for (index = 0; index < length; index++) { currentVal = inputArray[index]; diff --git a/src/mymemory.c b/src/mymemory.c index a93db2306..b6482f175 100644 --- a/src/mymemory.c +++ b/src/mymemory.c @@ -34,7 +34,7 @@ #include "include/generic.h" // for LOGERROR, byte, isnull #include "include/SW_datastructs.h" // for LOG_INFO #include // for free, malloc, realloc -#include // for strlen, memcpy, memset, strcpy +#include // for strlen, memset, strcpy /* =================================================== */ /* Global Function Definitions */ @@ -60,7 +60,7 @@ char *Str_Dup(const char *s, LOG_INFO *LogInfo) { return NULL; // Exit function prematurely due to error } - strcpy(p, s); + strcpy(p, s); // NOLINT(clang-analyzer-security.insecureAPI.strcpy) return p; } @@ -80,7 +80,17 @@ void *Mem_Malloc(size_t size, const char *funcname, LOG_INFO *LogInfo) { consistent with other modules. -------------------------------------------*/ - void *p; + void *p = NULL; + + if (LogInfo->stopRun) { + LogError( + LogInfo, + LOGERROR, + "Mem_Malloc() by %s() called with existing error.", + funcname + ); + return p; // Exit function prematurely due to error + } p = malloc(size); @@ -139,7 +149,7 @@ void *Mem_ReAlloc(void *block, size_t sizeNew, LOG_INFO *LogInfo) { return NULL; } - void *res = (void *) realloc(block, sizeNew); + void *res = realloc(block, sizeNew); if (isnull(res)) { free(block); @@ -173,5 +183,49 @@ void Mem_Copy(void *dest, const void *src, size_t n) { memcpy(dest, src, n); } +/* +@brief Custom functionality that mimics that of `sw_memccpy()` and is used +when the correct dependencies for `sw_memccpy()` are not available + +@note This implementation is based off one suggested by Martin Sebor in +the article +https://developers.redhat.com/blog/2019/08/12/efficient-string-copying-and-concatenation-in-c# + +@note This function uses the compiler macro '__restrict' instead of simply +'restrict' due to C++ standards not supporting it, so '__restrict' is +compatible in Clang and GCC + +@param[in,out] dest Character array to copy into +@param[in] src Character array to copy from +@param[in] c Target character which, upon finding, is one of the stopping +condiditions +@param[in] n The number of bytes to copy from src to dest, and is the +second stopping condition + +@return +Upon finding the target character: the pointer to the next byte in dest after +the copy Upon not finding the target character: null pointer character +*/ +void *sw_memccpy_custom( + void *__restrict dest, void *__restrict src, int c, size_t n +) { + char *s = (char *) src; + char *ret = (char *) dest; + + while (n > 0) { + *ret = *s; + + if ((unsigned char) *ret == (unsigned char) c) { + return ret + 1; + } + + ret++; + s++; + n--; + } + + return 0; +} + /* =============== end of block from gen_funcs.c ----------------- */ /* ================ see also the end of this file ------------------ */ diff --git a/src/rands.c b/src/rands.c index 2583a046c..a9c8aede2 100644 --- a/src/rands.c +++ b/src/rands.c @@ -59,7 +59,9 @@ even if they occurred during the same system time. @param[in,out] pcg_rng The random number generator to set. */ void RandSeed( - unsigned long initstate, unsigned long initseq, sw_random_t *pcg_rng + unsigned long initstate, + unsigned long initseq, + sw_random_t *pcg_rng // NOLINT(readability-non-const-parameter) ) { // R uses its own random number generators #ifndef RSOILWAT @@ -93,6 +95,7 @@ If `pcg_rng` was not initialized with `RandSeed()`, then the first call to @return A pseudo-random number between 0 and 1. */ +// NOLINTNEXTLINE(readability-non-const-parameter) double RandUni(sw_random_t *pcg_rng) { double res; @@ -122,7 +125,11 @@ double RandUni(sw_random_t *pcg_rng) { \return Random number between the two bounds defined. */ -int RandUniIntRange(const long first, const long last, sw_random_t *pcg_rng) { +long RandUniIntRange( + const long first, + const long last, + sw_random_t *pcg_rng // NOLINT(readability-non-const-parameter) +) { /* History: Return a randomly selected integer between first and last, inclusive. @@ -140,7 +147,9 @@ int RandUniIntRange(const long first, const long last, sw_random_t *pcg_rng) { - first = -5, last = 5, result = 0 */ - long f, l, res; + long f; + long l; + long res; if (first == last) { return first; @@ -163,7 +172,7 @@ int RandUniIntRange(const long first, const long last, sw_random_t *pcg_rng) { (void) pcg_rng; // silence compile warnings [-Wunused-parameter] GetRNGstate(); - res = (long) runif(f, l); + res = (long) runif((double) f, (double) l); PutRNGstate(); #endif @@ -197,7 +206,9 @@ float RandUniFloatRange( - first = 4.5, last = -1.1, result = -.32 - first = -5, last = 5, result = 0 */ - float f, l, r; + float f; + float l; + float r; if (max == min) { return min; @@ -243,7 +254,11 @@ void RandUniList( LOG_INFO *LogInfo ) { - long i, j, c, range, *klist; + long i; + long j; + long c; + long range; + long *klist; range = last - first + 1; @@ -268,7 +283,7 @@ void RandUniList( /* if count <= 2, handle things directly */ /* for less complexity and more speed */ if (count <= 2) { - list[0] = (long) RandUniIntRange(first, last, pcg_rng); + list[0] = RandUniIntRange(first, last, pcg_rng); if (count == 2) { while ((list[1] = RandUniIntRange(first, last, pcg_rng)) == list[0]) @@ -334,7 +349,11 @@ If compiled with defined `RSOILWAT`, then `rnorm()` from header @param stddev Standard deviation of the distribution. @param[in,out] *pcg_rng The random number generator to use. */ -double RandNorm(double mean, double stddev, sw_random_t *pcg_rng) { +double RandNorm( + double mean, + double stddev, + sw_random_t *pcg_rng // NOLINT(readability-non-const-parameter) +) { /* History: cwb - 6/20/00 This routine is @@ -353,7 +372,9 @@ double RandNorm(double mean, double stddev, sw_random_t *pcg_rng) { double res; #ifndef RSOILWAT - double v1, v2, r; + double v1; + double v2; + double r; #ifdef RANDNORMSTATIC /* original, non-reentrant code: issue #326 */ @@ -428,27 +449,27 @@ This code is distributed under the GNU LGPL license. @param[out] LogInfo Holds information on warnings and errors \return A random variate of a beta distribution. */ -float RandBeta(float aa, float bb, sw_random_t *pcg_rng, LOG_INFO *LogInfo) { - float a; - float alpha; - float b; - float beta; - float delta; - float gamma; - float k1; - float k2; - const float log4 = 1.3862943611198906188; - const float log5 = 1.6094379124341003746; - float r; - float s; - float t; - float u1; - float u2; - float v; - float value; - float w; - float y; - float z; +double RandBeta(double aa, double bb, sw_random_t *pcg_rng, LOG_INFO *LogInfo) { + double a; + double alpha; + double b; + double beta; + double delta; + double gamma; + double k1; + double k2; + const double log4 = 1.3862943611198906188; + const double log5 = 1.6094379124341003746; + double r; + double s; + double t; + double u1; + double u2; + double v; + double value; + double w; + double y; + double z; if (aa <= 0.0) { LogError(LogInfo, LOGERROR, "RandBeta - Fatal error: AA <= 0.0\n"); diff --git a/tests/gtests/sw_maintest.cc b/tests/gtests/sw_maintest.cc index cc6de4cbc..4facc02a3 100644 --- a/tests/gtests/sw_maintest.cc +++ b/tests/gtests/sw_maintest.cc @@ -12,7 +12,7 @@ The paths are relative to the unit-test executable which is located at bin/ of the SOILWAT2 repository */ -const char *dir_test = "./tests/example"; +const char *const dir_test = "./tests/example"; /* Naming scheme for unit tests https://google.github.io/googletest/faq.html @@ -40,7 +40,7 @@ int main(int argc, char **argv) { /*--- Imitate 'SW_Main.c/main()' */ // Emulate 'sw_init_args()' - if (!ChDir(dir_test)) { + if (ChDir(dir_test) == 0u) { sw_printf("Invalid project directory (%s)", dir_test); } diff --git a/tests/gtests/sw_testhelpers.cc b/tests/gtests/sw_testhelpers.cc index 6aafb013e..bbda90ef4 100644 --- a/tests/gtests/sw_testhelpers.cc +++ b/tests/gtests/sw_testhelpers.cc @@ -1,6 +1,6 @@ #include "tests/gtests/sw_testhelpers.h" -#include "include/generic.h" // for RealF, swFALSE, swTRUE, RealD +#include "include/generic.h" // for swFALSE, swTRUE #include "include/myMemory.h" // for Str_Dup #include "include/SW_Control.h" // for SW_CTL_alloc_outptrs, SW_CTL_clear_m... #include "include/SW_Files.h" // for eFirst @@ -13,9 +13,12 @@ #include // for strcpy +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) SW_RUN template_SW_Run; SW_DOMAIN template_SW_Domain; +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + /** @brief Creates soil layers based on function arguments (instead of reading them from an input file as _read_layers() does) @@ -34,7 +37,7 @@ void create_test_soillayers( ) { if (nlayers <= 0 || nlayers > MAX_LAYERS) { - fprintf( + (void) fprintf( stderr, "create_test_soillayers(): " "requested number of soil layers (n = %d) is not accepted.\n", @@ -44,53 +47,54 @@ void create_test_soillayers( exit(-1); } - RealF dmax[MAX_LAYERS] = {5, 6, 10, 11, 12, 20, 21, 22, 25, - 30, 40, 41, 42, 50, 51, 52, 53, 54, - 55, 60, 70, 80, 90, 110, 150}; - RealF bulkd[MAX_LAYERS] = {1.430, 1.410, 1.390, 1.390, 1.380, 1.150, 1.130, - 1.130, 1.430, 1.410, 1.390, 1.390, 1.380, 1.150, - 1.130, 1.130, 1.430, 1.410, 1.390, 1.390, 1.380, - 1.150, 1.130, 1.130, 1.400}; - RealF f_gravel[MAX_LAYERS] = {0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, - 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, - 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2}; - RealF evco[MAX_LAYERS] = {0.813, 0.153, 0.034, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - RealF trco_grass[MAX_LAYERS] = {0.0158, 0.0155, 0.0314, 0.0314, 0.0314, + double dmax[MAX_LAYERS] = {5, 6, 10, 11, 12, 20, 21, 22, 25, + 30, 40, 41, 42, 50, 51, 52, 53, 54, + 55, 60, 70, 80, 90, 110, 150}; + double bulkd[MAX_LAYERS] = {1.430, 1.410, 1.390, 1.390, 1.380, 1.150, 1.130, + 1.130, 1.430, 1.410, 1.390, 1.390, 1.380, 1.150, + 1.130, 1.130, 1.430, 1.410, 1.390, 1.390, 1.380, + 1.150, 1.130, 1.130, 1.400}; + double f_gravel[MAX_LAYERS] = {0.1, 0.1, 0.1, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, + 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2}; + double evco[MAX_LAYERS] = {0.813, 0.153, 0.034, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0}; + double trco_grass[MAX_LAYERS] = {0.0158, 0.0155, 0.0314, 0.0314, 0.0314, + 0.0624, 0.0624, 0.0624, 0.0155, 0.0155, + 0.0314, 0.0314, 0.0314, 0.0624, 0.0624, + 0.0624, 0.0155, 0.0155, 0.0314, 0.0314, + 0.0314, 0.0624, 0.0624, 0.0624, 0.0625}; + double trco_shrub[MAX_LAYERS] = {0.0413, 0.0294, 0.055, 0.0547, 0.0344, + 0.0341, 0.0316, 0.0316, 0.0419, 0.0294, + 0.055, 0.0547, 0.0344, 0.0341, 0.0316, + 0.0316, 0.0419, 0.0294, 0.0550, 0.0547, + 0.0344, 0.0341, 0.0316, 0.0316, 0.0625}; + double trco_tree[MAX_LAYERS] = {0.0158, 0.0155, 0.0314, 0.0314, 0.0314, 0.0624, 0.0624, 0.0624, 0.0155, 0.0155, 0.0314, 0.0314, 0.0314, 0.0624, 0.0624, 0.0624, 0.0155, 0.0155, 0.0314, 0.0314, 0.0314, 0.0624, 0.0624, 0.0624, 0.0625}; - RealF trco_shrub[MAX_LAYERS] = {0.0413, 0.0294, 0.055, 0.0547, 0.0344, + double trco_forb[MAX_LAYERS] = {0.0413, 0.0294, 0.055, 0.0547, 0.0344, 0.0341, 0.0316, 0.0316, 0.0419, 0.0294, 0.055, 0.0547, 0.0344, 0.0341, 0.0316, 0.0316, 0.0419, 0.0294, 0.0550, 0.0547, 0.0344, 0.0341, 0.0316, 0.0316, 0.0625}; - RealF trco_tree[MAX_LAYERS] = {0.0158, 0.0155, 0.0314, 0.0314, 0.0314, - 0.0624, 0.0624, 0.0624, 0.0155, 0.0155, - 0.0314, 0.0314, 0.0314, 0.0624, 0.0624, - 0.0624, 0.0155, 0.0155, 0.0314, 0.0314, - 0.0314, 0.0624, 0.0624, 0.0624, 0.0625}; - RealF trco_forb[MAX_LAYERS] = {0.0413, 0.0294, 0.055, 0.0547, 0.0344, - 0.0341, 0.0316, 0.0316, 0.0419, 0.0294, - 0.055, 0.0547, 0.0344, 0.0341, 0.0316, - 0.0316, 0.0419, 0.0294, 0.0550, 0.0547, - 0.0344, 0.0341, 0.0316, 0.0316, 0.0625}; - RealF psand[MAX_LAYERS] = {0.51, 0.44, 0.35, 0.32, 0.31, 0.32, 0.57, - 0.57, 0.51, 0.44, 0.35, 0.32, 0.31, 0.32, - 0.57, 0.57, 0.51, 0.44, 0.35, 0.32, 0.31, - 0.32, 0.57, 0.57, 0.58}; - RealF pclay[MAX_LAYERS] = {0.15, 0.26, 0.41, 0.45, 0.47, 0.47, 0.28, - 0.28, 0.15, 0.26, 0.41, 0.45, 0.47, 0.47, - 0.28, 0.28, 0.15, 0.26, 0.41, 0.45, 0.47, - 0.47, 0.28, 0.28, 0.29}; - RealF imperm[MAX_LAYERS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - RealF soiltemp[MAX_LAYERS] = {-1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}; - - int nRegions = 3; - RealD regionLowerBounds[3] = {20., 50., 100.}; + double psand[MAX_LAYERS] = {0.51, 0.44, 0.35, 0.32, 0.31, 0.32, 0.57, + 0.57, 0.51, 0.44, 0.35, 0.32, 0.31, 0.32, + 0.57, 0.57, 0.51, 0.44, 0.35, 0.32, 0.31, + 0.32, 0.57, 0.57, 0.58}; + double pclay[MAX_LAYERS] = {0.15, 0.26, 0.41, 0.45, 0.47, 0.47, 0.28, + 0.28, 0.15, 0.26, 0.41, 0.45, 0.47, 0.47, + 0.28, 0.28, 0.15, 0.26, 0.41, 0.45, 0.47, + 0.47, 0.28, 0.28, 0.29}; + double imperm[MAX_LAYERS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + double soiltemp[MAX_LAYERS] = {-1, -1, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2}; + + int const nRegions = 3; + double regionLowerBounds[3] = {20., 50., 100.}; set_soillayers( SW_VegProd, @@ -121,9 +125,9 @@ void setup_SW_Site_for_tests(SW_SITE *SW_Site) { SW_Site->deepdrain = swTRUE; - SW_Site->_SWCMinVal = 100; - SW_Site->_SWCWetVal = 15; - SW_Site->_SWCInitVal = 15; + SW_Site->SWCMinVal = 100; + SW_Site->SWCWetVal = 15; + SW_Site->SWCInitVal = 15; SW_Site->stMaxDepth = 990; SW_Site->stDeltaX = 15; @@ -131,10 +135,20 @@ void setup_SW_Site_for_tests(SW_SITE *SW_Site) { SW_Site->slow_drain_coeff = 0.02; SW_Site->site_has_swrcp = swFALSE; - strcpy(SW_Site->site_swrc_name, (char *) "Campbell1974"); + (void) snprintf( + SW_Site->site_swrc_name, + sizeof SW_Site->site_swrc_name, + "%s", + "Campbell1974" + ); SW_Site->site_swrc_type = encode_str2swrc(SW_Site->site_swrc_name, &LogInfo); - strcpy(SW_Site->site_ptf_name, (char *) "Cosby1984AndOthers"); + (void) snprintf( + SW_Site->site_ptf_name, + sizeof SW_Site->site_ptf_name, + "%s", + "Cosby1984AndOthers" + ); SW_Site->site_ptf_type = encode_str2ptf(SW_Site->site_ptf_name); } @@ -163,7 +177,7 @@ int setup_testGlobalSoilwatTemplate() { template_SW_Domain.PathInfo.InFiles[eFirst] = Str_Dup(DFLT_FIRSTFILE, &LogInfo); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } @@ -171,14 +185,14 @@ int setup_testGlobalSoilwatTemplate() { userSUID = 0; SW_CTL_setup_domain(userSUID, &template_SW_Domain, &LogInfo); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } SW_CTL_setup_model( &template_SW_Run, &template_SW_Domain.OutDom, swTRUE, &LogInfo ); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } template_SW_Run.Model.doOutput = swFALSE; /* turn off output during tests */ @@ -186,13 +200,13 @@ int setup_testGlobalSoilwatTemplate() { SW_MDL_get_ModelRun( &template_SW_Run.Model, &template_SW_Domain, NULL, &LogInfo ); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } /* allocate memory for output pointers */ SW_CTL_alloc_outptrs(&template_SW_Run, &LogInfo); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } @@ -202,7 +216,7 @@ int setup_testGlobalSoilwatTemplate() { &template_SW_Domain.PathInfo, &LogInfo ); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } @@ -224,12 +238,12 @@ int setup_testGlobalSoilwatTemplate() { template_SW_Run.Model.days_in_month, &LogInfo ); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } SW_CTL_init_run(&template_SW_Run, &LogInfo); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } @@ -240,12 +254,12 @@ int setup_testGlobalSoilwatTemplate() { &template_SW_Domain.OutDom, &LogInfo ); - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { goto finishProgram; } finishProgram: { - if (LogInfo.stopRun) { + if (LogInfo.stopRun != 0u) { success = 1; // failure } } diff --git a/tests/gtests/sw_testhelpers.h b/tests/gtests/sw_testhelpers.h index 4e32b1fa4..49f19ce09 100644 --- a/tests/gtests/sw_testhelpers.h +++ b/tests/gtests/sw_testhelpers.h @@ -92,4 +92,4 @@ using WeatherFixtureTest = AllTestFixture; using WaterBalanceFixtureTest = AllTestFixture; -using SpinUpTest = AllTestFixture; +using SpinUpFixtureTest = AllTestFixture; diff --git a/tests/gtests/test_SW_Carbon.cc b/tests/gtests/test_SW_Carbon.cc index 2657c45c8..7b43a8787 100644 --- a/tests/gtests/test_SW_Carbon.cc +++ b/tests/gtests/test_SW_Carbon.cc @@ -5,7 +5,7 @@ #include "include/SW_VegProd.h" // for BIO_INDEX, WUE_INDEX #include "tests/gtests/sw_testhelpers.h" // for CarbonFixtureTest #include "gtest/gtest.h" // for Message, Test, CmpHelperGT -#include // for strcpy +#include // for snprintf namespace { // Test the SW_Carbon constructor 'SW_CBN_construct' @@ -22,7 +22,8 @@ TEST(CarbonTest, CarbonConstructor) { // Test reading yearly CO2 data from disk file TEST_F(CarbonFixtureTest, CarbonReadInputFile) { - TimeInt year, simendyr = SW_Run.Model.endyr + SW_Run.Model.addtl_yr; + TimeInt year; + TimeInt const simendyr = SW_Run.Model.endyr + SW_Run.Model.addtl_yr; double sum_CO2; // Test if CO2-effects are turned off -> no CO2 concentration data are read @@ -45,7 +46,10 @@ TEST_F(CarbonFixtureTest, CarbonReadInputFile) { // Test if CO2-effects are turned on -> CO2 concentration data are read from // file SW_CBN_construct(&SW_Run.Carbon); - strcpy(SW_Run.Carbon.scenario, "RCP85"); + (void) snprintf( + SW_Run.Carbon.scenario, sizeof SW_Run.Carbon.scenario, "%s", "RCP85" + ); + SW_Run.Carbon.use_wue_mult = 1; SW_Run.Carbon.use_bio_mult = 1; SW_Run.Model.addtl_yr = 0; @@ -63,11 +67,14 @@ TEST_F(CarbonFixtureTest, CarbonReadInputFile) { // Test the calculation of CO2-effect multipliers TEST_F(CarbonFixtureTest, CarbonCO2multipliers) { - TimeInt year, simendyr = SW_Run.Model.endyr + SW_Run.Model.addtl_yr; + TimeInt year; + TimeInt const simendyr = SW_Run.Model.endyr + SW_Run.Model.addtl_yr; int k; SW_CBN_construct(&SW_Run.Carbon); - strcpy(SW_Run.Carbon.scenario, "RCP85"); + (void) snprintf( + SW_Run.Carbon.scenario, sizeof SW_Run.Carbon.scenario, "%s", "RCP85" + ); SW_Run.Carbon.use_wue_mult = 1; SW_Run.Carbon.use_bio_mult = 1; SW_Run.Model.addtl_yr = 0; diff --git a/tests/gtests/test_SW_Flow_Lib.cc b/tests/gtests/test_SW_Flow_Lib.cc index e3312c163..9b5abc189 100644 --- a/tests/gtests/test_SW_Flow_Lib.cc +++ b/tests/gtests/test_SW_Flow_Lib.cc @@ -1,4 +1,4 @@ -#include "include/generic.h" // for RealD, swFALSE, swTRUE +#include "include/generic.h" // for swFALSE, swTRUE #include "include/rands.h" // for RandNorm, RandSeed #include "include/SW_datastructs.h" // for LOG_INFO, SW_SITE, SW_VEGPROD #include "include/SW_Defines.h" // for MAX_LAYERS, ForEachSoilLayer @@ -10,11 +10,6 @@ #include // for fixed #include // for NULL -sw_random_t flow_rng; -// SW_SOILWAT_OUTPUTS *swo = NULL; - -int k; - namespace { // Test the veg interception function 'veg_intercepted_water' TEST(SWFlowTest, SWFlowVegInterceptedWater) { @@ -25,8 +20,13 @@ TEST(SWFlowTest, SWFlowVegInterceptedWater) { ForEachVegType(k) { // declare inputs - double bLAI, ppt, pptleft, wintveg, store; - double scale = 1.0, m = 1.0; + double bLAI; + double ppt; + double pptleft; + double wintveg; + double store; + double const scale = 1.0; + double const m = 1.0; // Test expectation when there is no leaf-area bLAI = 0.0, ppt = 5.0, pptleft = ppt, store = 0.0; @@ -91,8 +91,13 @@ TEST(SWFlowTest, SWFlowLitterInterceptedWater) { ForEachVegType(k) { // declare inputs - double blitter, ppt, pptleft, wintlit, store; - double scale = 1.0, m = 1.0; + double blitter; + double ppt; + double pptleft; + double wintlit; + double store; + double scale = 1.0; + double const m = 1.0; // Test expectation when there is no litter blitter = 0.0, ppt = 5.0, pptleft = ppt, wintlit = 0.0, store = 0.0; @@ -112,10 +117,9 @@ TEST(SWFlowTest, SWFlowLitterInterceptedWater) { EXPECT_EQ(pptleft, ppt); // Test expectations when pptleft is 0 - pptleft = 0.0, scale = 0.5, blitter = 5.0; - // Test expectations when there is no throughfall + scale = 0.5; blitter = 200.0, ppt = 0.0, pptleft = ppt, wintlit = 0.0, store = 0.0; litter_intercepted_water( @@ -157,16 +161,21 @@ TEST(SWFlowTest, SWFlowLitterInterceptedWater) { // Test infiltration under high water function, 'infiltrate_water_high' TEST(SWFlowTest, SWFlowSaturatedPercolation) { - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; // declare inputs - double pptleft = 5.0, standingWater, drainout; + double pptleft = 5.0; + double standingWater; + double drainout; // ***** Tests when nlyrs = 1 ***** // /// provide inputs int nlyrs = 1; - double swc[1] = {0.8}, swcfc[1] = {1.1}, swcsat[1] = {1.6}, - impermeability[1] = {0.}, drain[1] = {0.}; + double swc[1] = {0.8}; + double swcfc[1] = {1.1}; + double swcsat[1] = {1.6}; + double impermeability[1] = {0.}; + double drain[1] = {0.}; infiltrate_water_high( swc, @@ -447,12 +456,13 @@ TEST(SWFlowTest, SWFlowTranspWeightedAvg) { // INPUTS double swp_avg = 10; unsigned int i; - unsigned int n_tr_rgns = 1, n_layers = 1; + unsigned int n_tr_rgns = 1; + unsigned int n_layers = 1; unsigned int tr_regions[1] = {1}; // 1-4 double swc[1] = {12}; // INPUTS for expected outputs - double swp_avgExpected1 = 1.5992088; + double const swp_avgExpected1 = 1.5992088; // Setup soil layers create_test_soillayers(n_layers, &SW_VegProd, &SW_Site, &LogInfo); @@ -488,7 +498,7 @@ TEST(SWFlowTest, SWFlowTranspWeightedAvg) { double swc2[25]; // INPUTS for expected OUTPUTS - double swp_avgExpectedM = 1.7389131503001496; + double const swp_avgExpectedM = 1.7389131503001496; // Setup soil layers create_test_soillayers(n_layers, &SW_VegProd, &SW_Site, &LogInfo); @@ -522,10 +532,14 @@ TEST(SWFlowTest, SWFlowTranspWeightedAvg) { // Test EsT_partitioning by manipulating fbse and fbst variables. TEST(SWFlowTest, SWFlowEsTPartitioning) { // INPUTS - double fbse = 0, fbst = 0, blivelai = 0.002, lai_param = 2; + double fbse = 0; + double fbst = 0; + double blivelai = 0.002; + double lai_param = 2; // Test when fbse > bsemax - double fbseExpected = 0.995, fbstExpected = 0.005; + double fbseExpected = 0.995; + double fbstExpected = 0.005; EsT_partitioning(&fbse, &fbst, blivelai, lai_param); EXPECT_NEAR(fbse, fbseExpected, tol6); // fbse is expected to be 0.995 @@ -566,10 +580,19 @@ TEST(SWFlowTest, SWFlowPotentialSoilEvaporation) { ForEachVegType(k) { SW_VegProd.veg[k].SWPcrit = 20; } - unsigned int i, nelyrs; - double bserate = 0, totagb, Es_param_limit = 999., fbse = 0.813, fbse0 = 0., - petday = 0.1, petday0 = 0., shift = 45, shape = 0.1, inflec = 0.25, - range = 0.5; + unsigned int i; + unsigned int nelyrs; + double bserate = 0; + double totagb; + double const Es_param_limit = 999.; + double const fbse = 0.813; + double const fbse0 = 0.; + double const petday = 0.1; + double const petday0 = 0.; + double const shift = 45; + double const shape = 0.1; + double const inflec = 0.25; + double const range = 0.5; double swc[25]; @@ -714,9 +737,14 @@ TEST(SWFlowTest, SWFlowPotentialSoilEvaporation2) { ForEachVegType(k) { SW_VegProd.veg[k].SWPcrit = 20; } // INPUTS - unsigned int nelyrs, i; - double bserate = 0, petday = 0.1, shift = 45, shape = 0.1, inflec = 0.25, - range = 0.8; + unsigned int nelyrs; + unsigned int i; + double bserate = 0; + double const petday = 0.1; + double const shift = 45; + double const shape = 0.1; + double const inflec = 0.25; + double const range = 0.8; double swc[25]; // Loop over tests with varying number of soil layers @@ -769,11 +797,23 @@ TEST(SWFlowTest, SWFlowPotentialSoilEvaporation2) { // Test pot_transp by manipulating biolive and biodead input variables TEST(SWFlowTest, SWFlowPotentialTranspiration) { // INPUTS - double bstrate = 0, swpavg = 0.8, biolive = -0.8, biodead = 0.2, fbst = 0.8, - petday = 0.1, swp_shift = 45, swp_shape = 0.1, swp_inflec = 0.25, - swp_range = 0.3, shade_scale = 1.1, shade_deadmax = 0.9, - shade_xinflex = 0.4, shade_slope = 0.9, shade_yinflex = 0.3, - shade_range = 0.8, co2_wue_multiplier = 2.1; + double bstrate = 0; + double const swpavg = 0.8; + double biolive = -0.8; + double biodead = 0.2; + double const fbst = 0.8; + double const petday = 0.1; + double const swp_shift = 45; + double const swp_shape = 0.1; + double const swp_inflec = 0.25; + double const swp_range = 0.3; + double const shade_scale = 1.1; + double const shade_deadmax = 0.9; + double const shade_xinflex = 0.4; + double const shade_slope = 0.9; + double const shade_yinflex = 0.3; + double const shade_range = 0.8; + double const co2_wue_multiplier = 2.1; // Begin Test for if biolive < 0 pot_transp( @@ -884,8 +924,12 @@ TEST(SWFlowTest, SWFlowPotentialTranspiration) { // Test result for watrate by manipulating variable petday TEST(SWFlowTest, SWFlowWatrate) { // INPUTS - double swp = 0.8, petday = 0.1, shift = 45, shape = 0.1, inflec = 0.25, - range = 0.8; + double const swp = 0.8; + double petday = 0.1; + double const shift = 45; + double const shape = 0.1; + double const inflec = 0.25; + double const range = 0.8; // Begin Test for if petday < .2 double watExpected = 0.630365; @@ -927,10 +971,14 @@ TEST(SWFlowTest, SWFlowWatrate) { // Test evap_fromSurface by manipulating water_pool and evap_rate variables TEST(SWFlowTest, SWFlowSurfaceEvaporation) { // INPUTS - double water_pool = 1, evap_rate = 0.33, aet = 0.53; + double water_pool = 1; + double evap_rate = 0.33; + double aet = 0.53; // Begin Test for when water_pool > evap_rate - double aetExpected = 0.86, evapExpected = 0.33, waterExpected = 0.67; + double aetExpected = 0.86; + double evapExpected = 0.33; + double const waterExpected = 0.67; evap_fromSurface(&water_pool, &evap_rate, &aet); // Variable aet is expected to be 0.86 with current inputs @@ -979,14 +1027,20 @@ TEST(SWFlowTest, SWFlowRemoveFromSoil) { // INPUTS - unsigned int nlyrs, i; - double aet_init = 0.33, aet, rate = 0.62; - double swc_init[MAX_LAYERS], swc[MAX_LAYERS]; + unsigned int nlyrs; + unsigned int i; + double const aet_init = 0.33; + double aet; + double const rate = 0.62; + double swc_init[MAX_LAYERS]; + double swc[MAX_LAYERS]; double swcmin[MAX_LAYERS] = {0.}; - double qty[MAX_LAYERS] = {0.}, qty_sum = 0.; - double coeff[MAX_LAYERS], coeffZero[MAX_LAYERS] = {0.}; + double qty[MAX_LAYERS] = {0.}; + double qty_sum = 0.; + double coeff[MAX_LAYERS]; + double coeffZero[MAX_LAYERS] = {0.}; - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; // Loop over tests with varying number of soil layers @@ -1179,12 +1233,16 @@ TEST(SWFlowTest, SWFlowPercolateUnsaturated) { // INPUTS - unsigned int nlyrs, i; - double sum_delta_swc, small, drainout, standingWater; + unsigned int nlyrs; + unsigned int i; + double sum_delta_swc; + double small; + double drainout; + double standingWater; double swc[MAX_LAYERS]; double drain[MAX_LAYERS]; - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; // Loop over tests with varying number of soil layers @@ -1414,25 +1472,33 @@ TEST(SWFlowTest, SWFlowHydraulicRedistribution) { ForEachVegType(k) { SW_VegProd.veg[k].SWPcrit = 20; } // INPUTS - unsigned int nlyrs, i, year = 1980, doy = 1; - double maxCondroot = -0.2328, swp50 = 1.2e12, shapeCond = 1, scale = 0.3; - double swc[MAX_LAYERS], hydred[MAX_LAYERS] = {0.}; - double swcExpected = 0., hydredExpected = 0.; + unsigned int nlyrs; + unsigned int i; + unsigned int const year = 1980; + unsigned int const doy = 1; + double const maxCondroot = -0.2328; + double const swp50 = 1.2e12; + double const shapeCond = 1; + double const scale = 0.3; + double swc[MAX_LAYERS]; + double hydred[MAX_LAYERS] = {0.}; + double swcExpected = 0.; + double hydredExpected = 0.; - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; // INPUTS for expected outcomes - double swcExpected_1L[1] = {0.8258887}; - double hydredExpected_1L[1] = {0.}; + double const swcExpected_1L[1] = {0.8258887}; + double const hydredExpected_1L[1] = {0.}; - double swcExpected_MAXL[MAX_LAYERS] = { + double const swcExpected_MAXL[MAX_LAYERS] = { 0.8258890, 0.2068467, 0.9920907, 0.2581966, 0.2329534, 1.8503562, 0.1678064, 0.1678063, 0.4403078, 0.9193770, 2.2045783, 0.2295204, 0.2329534, 1.8503562, 0.1678063, 0.1678063, 0.1466935, 0.1838611, 0.2205380, 1.1471038, 2.3287794, 2.3129346, 1.6781799, 3.3564146, 6.7275094 }; - double hydredExpected_MAXL[MAX_LAYERS] = { + double const hydredExpected_MAXL[MAX_LAYERS] = { 0.000000e+00, -2.436254e-05, 3.723615e-05, 1.105724e-04, 7.844259e-05, 3.179664e-05, -1.7262914e-05, -1.726291e-05, -1.6618943e-04, -5.0191450e-05, 1.491759e-05, 1.105724e-04, diff --git a/tests/gtests/test_SW_Flow_Lib_PET.cc b/tests/gtests/test_SW_Flow_Lib_PET.cc index e653f9cbe..b1cee3b00 100644 --- a/tests/gtests/test_SW_Flow_Lib_PET.cc +++ b/tests/gtests/test_SW_Flow_Lib_PET.cc @@ -5,48 +5,48 @@ #include "include/SW_Flow_lib_PET.h" // for SW_PET_init_run, solar_radi... #include "include/SW_Main_lib.h" // for sw_fail_on_error, sw_init_logs #include "tests/gtests/sw_testhelpers.h" // for tol3, tol0, tol1, tol6, mis... -#include "gmock/gmock.h" // for StrEq #include "gtest/gtest.h" // for Test, EXPECT_NEAR, TestInfo... #include // for round, NAN, isfinite #include // for allocator #include // for char_traits, basic_ostream #include // for NULL (fprintf, fflush, FILE) -#if defined(SW2_PET_Test__petfunc_by_temps) || \ - defined(SW2_SolarPosition_Test__hourangles_by_lat_and_doy) || \ - defined(SW2_SolarPosition_Test__hourangles_by_lats) -#include // for strcat, strcpy -#endif - #if defined(SW2_SolarPosition_Test__hourangles_by_lat_and_doy) #include // for free, malloc #endif -using ::testing::StrEq; - namespace { // Test solar position TEST(AtmDemandTest, SolarPosSolarPosition) { - double declin, reldist, lat, - six_hours = 6. * swPI / 12., - // Min/max solar declination = angle of Earth's axial tilt/obliquity - // value for 2020 based on Astronomical Almanac 2010 - declin_max = 23.43668 * deg_to_rad, declin_min = -declin_max, - // Min/max relative sun-earth distance - // values based on Astronomical Almanac 2010 - reldist_max = 1.01671, reldist_min = 0.98329; - - int i, - // Dates of equinoxes and solstices (day of nonleap year): - // - March equinox (March 19-21) - // - June solstice (Jun 20-22) - // - September equinox (Sep 21-24) - // - December solistice (Dec 20-23) - doy_Mar_equinox[2] = {79, 81}, doy_Sep_equinox[2] = {264, 266}, - doy_Jun_solstice[2] = {171, 173}, doy_Dec_solstice[2] = {354, 357}, - // Dates of perihelion and aphelion - doy_perihelion[2] = {2, 5}, doy_aphelion[2] = {184, 187}; + double declin; + double reldist; + double lat; + double const six_hours = 6. * swPI / 12.; + // Min/max solar declination = angle of Earth's axial tilt/obliquity + // value for 2020 based on Astronomical Almanac 2010 + double const declin_max = 23.43668 * deg_to_rad; + double const declin_min = -declin_max; + // Min/max relative sun-earth distance + // values based on Astronomical Almanac 2010 + double const reldist_max = 1.01671; + double const reldist_min = 0.98329; + + int i; + + // Dates of equinoxes and solstices (day of nonleap year): + // - March equinox (March 19-21) + // - June solstice (Jun 20-22) + // - September equinox (Sep 21-24) + // - December solistice (Dec 20-23) + int const doy_Mar_equinox[2] = {79, 81}; + int const doy_Sep_equinox[2] = {264, 266}; + int const doy_Jun_solstice[2] = {171, 173}; + int const doy_Dec_solstice[2] = {354, 357}; + + // Dates of perihelion and aphelion + int const doy_perihelion[2] = {2, 5}; + int const doy_aphelion[2] = {184, 187}; for (i = 1; i <= 366; i++) { @@ -139,14 +139,29 @@ TEST(AtmDemandTest, SolarPosSW_HourAnglesSymmetries) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - int k, k2, ilat, itime, isl, iasp, - doys[14] = - {1, 17, 47, 75, 105, 135, 162, 198, 228, 258, 288, 318, 344, 366}, - doy_used[4][14], doy_Jun_solstice = 172; - double rad_to_hours = 12. / swPI, latitude, latitude_used[4][14], slope, - aspect, aspect_used[4][14], o[4][14][7], int_cos_theta[2], - int_sin_beta[2], daylength[4][14]; - std::ostringstream msg, msg2; + int k; + int k2; + int ilat; + int itime; + int isl; + int iasp; + int const doys[14] = { + 1, 17, 47, 75, 105, 135, 162, 198, 228, 258, 288, 318, 344, 366 + }; + int doy_used[4][14]; + int const doy_Jun_solstice = 172; + double const rad_to_hours = 12. / swPI; + double latitude; + double latitude_used[4][14]; + double slope; + double aspect; + double aspect_used[4][14]; + double o[4][14][7]; + double int_cos_theta[2]; + double int_sin_beta[2]; + double daylength[4][14]; + std::ostringstream msg; + std::ostringstream msg2; for (isl = 0; isl <= 8; isl++) { @@ -327,15 +342,45 @@ TEST(AtmDemandTest, SolarPosSW_HourAnglesSymmetries) { // Rscript // tools/rscripts/Rscript__SW2_SolarPosition_Test__hourangles_by_lat_and_doy.R // ``` + +int fname_SolarPosHourAnglesByLatAndDoy( + char *buffer, size_t bufsz, double slope, double aspect +) { + return snprintf( + buffer, + bufsz, + "%s/%s__%s%d__%s%d.%s", + "Output", + "Table__SW2_SolarPosition_Test__hourangles_by_lat_and_doy", + "slope", + (int) slope, + "aspect", + (int) aspect, + "csv" + ); +} + TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { - int k, ilat, idoy, isl, iasp, length_strnum; - double rad_to_hours = 12. / swPI, slope = 0., aspect = 0., - aspects[9] = {-180., -120., -90., -60., 0., 60., 90., 120., 180.}, - sun_angles[7], int_cos_theta[2], int_sin_beta[2], daylength_H, - daylength_T; + int k; + int ilat; + int idoy; + int isl; + int iasp; + int length_strnum; + const double rad_to_hours = 12. / swPI; + double slope = 0.; + double aspect = 0.; + double sun_angles[7]; + double int_cos_theta[2]; + double int_sin_beta[2]; + double daylength_H; + double daylength_T; + const double aspects[9] = { + -180., -120., -90., -60., 0., 60., 90., 120., 180. + }; FILE *fp; - char *strnum, fname[FILENAME_MAX]; + char *fname = NULL; SW_ATMD SW_AtmDemand; SW_PET_init_run(&SW_AtmDemand); // Init radiation memoization @@ -359,36 +404,19 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { */ // Output file - strcpy(fname, "Output/"); - strcat( - fname, - "Table__SW2_SolarPosition_Test__hourangles_by_lat_and_doy" + length_strnum = + fname_SolarPosHourAnglesByLatAndDoy(NULL, 0, slope, aspect); + fname = (char *) malloc(length_strnum + 1); + (void) fname_SolarPosHourAnglesByLatAndDoy( + fname, length_strnum + 1, slope, aspect ); - strcat(fname, "__slope"); - length_strnum = snprintf(NULL, 0, "%d", (int) slope); - strnum = (char *) malloc(length_strnum + 1); - snprintf(strnum, length_strnum + 1, "%d", (int) slope); - strcat(fname, strnum); - free(strnum); - strnum = NULL; - - strcat(fname, "__aspect"); - length_strnum = snprintf(NULL, 0, "%d", (int) aspect); - strnum = (char *) malloc(length_strnum + 1); - snprintf(strnum, length_strnum + 1, "%d", (int) aspect); - strcat(fname, strnum); - free(strnum); - strnum = NULL; - - strcat(fname, ".csv"); - fp = OpenFile(fname, "w", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Column names - fprintf( + (void) fprintf( fp, "DOY, Latitude, Slope, Aspect, Declination" ", omega_indicator, " @@ -402,7 +430,7 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { // Loop over each DOY and 1-degree latitude bands for (ilat = -90; ilat <= 90; ilat++) { for (idoy = 1; idoy <= 366; idoy++) { - fprintf( + (void) fprintf( fp, "%d, %d, %.2f, %.2f, %f", idoy, @@ -424,7 +452,7 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { ); for (k = 0; k < 7; k++) { - fprintf(fp, ", %f", sun_angles[k]); + (void) fprintf(fp, ", %f", sun_angles[k]); } // Calculate numbers of daylight hours @@ -438,14 +466,14 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { sun_angles[5] - sun_angles[4]; } - fprintf( + (void) fprintf( fp, ", %f, %f\n", daylength_H * rad_to_hours, daylength_T * rad_to_hours ); - fflush(fp); + (void) fflush(fp); } // Re-init radiation memoization (for new latitude) @@ -455,6 +483,8 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { // Clean up CloseFile(&fp, &LogInfo); + free(fname); + fname = NULL; sw_fail_on_error(&LogInfo); // exit test program if unexpected error if (isl == 0) { @@ -479,14 +509,23 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLatAndDoy) { // tools/rscripts/Rscript__SW2_SolarPosition_Test__hourangles_by_lats.R // ``` TEST(AtmDemandTest, SolarPosHourAnglesByLats) { - int k, ilat, idoy, isl, iasp, iasp2; + int k; + int ilat; + int idoy; + int isl; + int iasp; + int iasp2; // doys: day of nonleap year Mar 18 (one day before equinox), Jun 21 // (solstice), Sep 24 (one day before equinox), and Dep 21 (solstice) - int doys[4] = {79, 172, 263, 355}; - double rlat, rslope, raspect; - double dangle2[5] = {-10., -1., 0., 1., 10.}; - double sun_angles[7], int_cos_theta[2], int_sin_beta[2]; + const int doys[4] = {79, 172, 263, 355}; + double rlat; + double rslope; + double raspect; + const double dangle2[5] = {-10., -1., 0., 1., 10.}; + double sun_angles[7]; + double int_cos_theta[2]; + double int_sin_beta[2]; FILE *fp; char fname[FILENAME_MAX]; @@ -498,14 +537,18 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLats) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - strcpy(fname, "Output/"); - strcat(fname, "Table__SW2_SolarPosition_Test__hourangles_by_lats.csv"); + (void) snprintf( + fname, + sizeof fname, + "%s", + "Output/Table__SW2_SolarPosition_Test__hourangles_by_lats.csv" + ); fp = OpenFile(fname, "w", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Column names - fprintf( + (void) fprintf( fp, "DOY, Latitude, Slope, Aspect, Declination" ", omega_indicator, " @@ -529,7 +572,7 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLats) { for (idoy = 0; idoy < 4; idoy++) { - fprintf( + (void) fprintf( fp, "%d, %.2f, %.2f, %.2f, %f", doys[idoy], @@ -551,10 +594,10 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLats) { ); for (k = 0; k < 7; k++) { - fprintf(fp, ", %f", sun_angles[k]); + (void) fprintf(fp, ", %f", sun_angles[k]); } - fprintf( + (void) fprintf( fp, ", %f, %f, %f, %f\n", int_cos_theta[0], @@ -563,7 +606,7 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLats) { int_sin_beta[1] ); - fflush(fp); + (void) fflush(fp); } // Re-init radiation memoization @@ -586,14 +629,22 @@ TEST(AtmDemandTest, SolarPosHourAnglesByLats) { TEST(AtmDemandTest, SolarRadiationExtraterrestrial) { SW_ATMD SW_AtmDemand; - unsigned int k1, k2, doy; - double lat, - lat_Madison_WI = 43. * deg_to_rad, // Duffie & Beckman 2013: Ex 1.6.1 - lat_StLouis_MO = 38.6 * deg_to_rad, // Duffie & Beckman 2013: Ex 2.11.1 - sun_angles[7], int_cos_theta[2], int_sin_beta[2], H_o[2], res_ratio; + unsigned int k1; + unsigned int k2; + unsigned int doy; + double lat; + // Madison_WI: Duffie & Beckman 2013: Ex 1.6.1 + double const lat_Madison_WI = 43. * deg_to_rad; + // StLouis_MO: Duffie & Beckman 2013: Ex 2.11.1 + double const lat_StLouis_MO = 38.6 * deg_to_rad; + double sun_angles[7]; + double int_cos_theta[2]; + double int_sin_beta[2]; + double H_o[2]; + double res_ratio; // Duffie & Beckman 2013: Table 1.10.1 - unsigned int doys_Table1_6_1[12] = { + unsigned int const doys_Table1_6_1[12] = { 17, 47, 75, 105, 135, 162, 198, 228, 258, 288, 318, 344 }; @@ -601,11 +652,11 @@ TEST(AtmDemandTest, SolarRadiationExtraterrestrial) { // during shifts between permanent sun and night // * lat = +85: Mar = 2.2, Sep = 6.4 // * lat = -90: Mar = 6.2, Sep = 1.4, Oct = 20.4 - double lats_Table1_10_1[9] = { + double const lats_Table1_10_1[9] = { 85., 45., 30., 15., 0., -10., -45., -60., -90. }; - double H_oh_Table1_10_1[9][12] = { + double const H_oh_Table1_10_1[9][12] = { // clang-format off {0.0, 0.0, NAN, 19.2, 37.0, 44.7, 41.0, 26.4, NAN, 0.0, 0.0, 0.0}, {12.2, 17.4, 25.1, 33.2, 39.2, 41.7, 40.4, 35.3, 27.8, 19.6, 13.3, 10.7}, @@ -752,15 +803,22 @@ TEST(AtmDemandTest, SolarRadiationGlobal) { unsigned int k; // Duffie & Beckman 2013: Table 1.6.1 - unsigned int doys_Table1_6_1[12] = { + unsigned int const doys_Table1_6_1[12] = { 17, 47, 75, 105, 135, 162, 198, 228, 258, 288, 318, 344 }; - unsigned int desc_rsds = 0; // `rsds` represents daily irradiation [MJ / m2] - - double H_gt, H_ot, H_oh, H_gh, rsds, cc, actual_vap_pressure; + // `rsds` represents daily irradiation [MJ / m2] + unsigned int const desc_rsds = 0; + + double H_gt; + double H_ot; + double H_oh; + double H_gh; + double rsds; + double cc; + double actual_vap_pressure; // Duffie & Beckman 2013: Example 2.19.1 - double H_Ex2_19_1[3][12] = { + double const H_Ex2_19_1[3][12] = { // clang-format off // H_oh [MJ / m2] {13.37, 18.81, 26.03, 33.78, 39.42, 41.78, 40.56, 35.92, 28.80, 20.90, 14.62, 11.91}, @@ -771,7 +829,7 @@ TEST(AtmDemandTest, SolarRadiationGlobal) { // clang-format on }; - double albedo[12] = { + double const albedo[12] = { 0.7, 0.7, 0.4, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4 }; @@ -786,25 +844,25 @@ TEST(AtmDemandTest, SolarRadiationGlobal) { // {66.25, 66.25, 70, 67.5, 65, 60, 57.5, 57.5, 60, 63.75, 72.5, 71.25}, // replaced observed with estimated values to match `H_Ex2_19_1`: // replaced ~ -61 + 1.661 * observed - double cloud_cover1[12] = { + double const cloud_cover1[12] = { 53., 47.5, 54., 53., 40., 35., 35., 30., 46., 50., 63., 52. }; // cloud_cover2: derived from observed `rsds` (`H_Ex2_19_1["H_gh"][]`) // and calculated `H_gh` // note: this should be identical to `cloud_cover1[]` - double cloud_cover2[12] = { + double const cloud_cover2[12] = { 39.9, 37.7, 45.6, 49.0, 36.2, 32.9, 30.6, 28.7, 40.6, 41.8, 50.7, 37.6 }; // Element 11: Relative Humidity (%), MN3HRLY (Statistic 94): Mean of // 3-Hourly Observations - double rel_humidity[12] = { + double const rel_humidity[12] = { 74.5, 73.1, 71.4, 66.3, 65.8, 68.3, 71.0, 74.4, 76.8, 73.2, 76.9, 78.5 }; // Element 01: Dry Bulb Temperature (deg C) - double air_temp_mean[12] = { + double const air_temp_mean[12] = { -8.9, -6.3, 0.2, 7.4, 13.6, 19, 21.7, 20.2, 15.4, 9.4, 1.9, -5.7 }; @@ -874,6 +932,7 @@ TEST(AtmDemandTest, SolarRadiationGlobal) { &LogInfo ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error + (void) H_gt; // Expect: observed `rsds` (for `desc_rsds = 0`) is equal to `H_gh` EXPECT_DOUBLE_EQ(rsds, H_gh); @@ -930,38 +989,36 @@ TEST(AtmDemandTest, SolarRadiationGlobal) { // Test saturation vapor pressure functions TEST(AtmDemandTest, PETsvp) { int i; - double - // Temperature [C] - temp_C[] = {-30, -20, -10, 0, 10, 20, 30, 40, 50, 60}, - - // Expected saturation vapor pressure [kPa] - check_svp, - expected_svp[] = - {0.0380009, - 0.103226, - 0.2598657, - 0.6112912, - 1.2281879, - 2.3393207, - 4.247004, - 7.3849328, - 12.3517837, - 19.9461044}, - - // Expected slope of svp - temperature curve [kPa / K] - check_svp_to_t, - expected_svp_to_T[] = { - 0.0039537, - 0.0099076, - 0.0230775, - 0.0503666, - 0.0822986, - 0.1449156, - 0.2437929, - 0.3937122, - 0.6129093, - 0.9231149 - }; + // Temperature [C] + double const temp_C[] = {-30, -20, -10, 0, 10, 20, 30, 40, 50, 60}; + double check_svp; + // Expected saturation vapor pressure [kPa] + double const expected_svp[] = { + 0.0380009, + 0.103226, + 0.2598657, + 0.6112912, + 1.2281879, + 2.3393207, + 4.247004, + 7.3849328, + 12.3517837, + 19.9461044 + }; + double check_svp_to_t; + // Expected slope of svp - temperature curve [kPa / K] + double const expected_svp_to_T[] = { + 0.0039537, + 0.0099076, + 0.0230775, + 0.0503666, + 0.0822986, + 0.1449156, + 0.2437929, + 0.3937122, + 0.6129093, + 0.9231149 + }; for (i = 0; i < 10; i++) { check_svp = svp(temp_C[i], &check_svp_to_t); @@ -981,32 +1038,43 @@ TEST(AtmDemandTest, PETpetfunc) { int i; - unsigned int doy = 2, desc_rsds = 0; - double check_pet, rsds = SW_MISSING, H_gt, H_oh, H_ot, H_gh; - double lat = 39. * deg_to_rad, elev = 1000., slope0 = 0.; - double sloped = 5. * deg_to_rad; - double aspect = -90. * deg_to_rad; // East-facing slope - double reflec = 0.15, temp = 25., RH = 61., windsp = 1.3, cloudcov = 71.; + unsigned int const doy = 2; + unsigned int const desc_rsds = 0; + double check_pet; + double const rsds = SW_MISSING; + double H_gt; + double H_oh; + double H_ot; + double H_gh; + double const lat = 39. * deg_to_rad; + double const elev = 1000.; + double const slope0 = 0.; + double const sloped = 5. * deg_to_rad; + double const aspect = -90. * deg_to_rad; // East-facing slope + double const reflec = 0.15; + double const temp = 25.; + double const RH = 61.; + double const windsp = 1.3; + double cloudcov = 71.; double actual_vap_pressure; // TEST `petfunc()` for varying average daily air temperature `avgtemp` [C] - double - // Inputs - avgtemps[] = {-30, -20, -10, 0, 10, 20, 30, 40, 50, 60}, - // Expected PET - expected_pet_avgtemps[] = { - 0.0100, - 0.0184, - 0.0346, - 0.0576, - 0.0896, - 0.1290, - 0.1867, - 0.2736, - 0.4027, - 0.5890 - }; + // Inputs + double const avgtemps[] = {-30, -20, -10, 0, 10, 20, 30, 40, 50, 60}; + // Expected PET + double const expected_pet_avgtemps[] = { + 0.0100, + 0.0184, + 0.0346, + 0.0576, + 0.0896, + 0.1290, + 0.1867, + 0.2736, + 0.4027, + 0.5890 + }; SW_PET_init_run(&SW_AtmDemand); // Init radiation memoization @@ -1042,15 +1110,14 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying latitude `lat` [± pi / 2] - double - // Inputs - lats[] = {-90., -45., 0., 45., 90.}, - // Expected PET - expected_pet_lats[] = { - 0.416576, 0.435964, 0.359670, 0.121564, 0.042131 - }; + // Inputs + double const lats[] = {-90., -45., 0., 45., 90.}; + // Expected PET + double const expected_pet_lats[] = { + 0.416576, 0.435964, 0.359670, 0.121564, 0.042131 + }; - double e_a = actualVaporPressure1(RH, temp); + double const e_a = actualVaporPressure1(RH, temp); for (i = 0; i < 5; i++) { SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1084,11 +1151,12 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying elevation [m a.s.l.] // Testing from -413 meters (Death Valley) to 8727 meters (~Everest). - double - // Inputs - elevs[] = {-413, 0, 1000, 4418, 8727}, - // Expected PET - expected_pet_elevs[] = {0.1670, 0.1634, 0.1550, 0.1305, 0.1093}; + // Inputs + double const elevs[] = {-413, 0, 1000, 4418, 8727}; + // Expected PET + double const expected_pet_elevs[] = { + 0.1670, 0.1634, 0.1550, 0.1305, 0.1093 + }; for (i = 0; i < 5; i++) { SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1122,11 +1190,12 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying slope [0 - pi / 2; radians] - double - // Inputs - slopes[] = {0., 15., 34., 57., 90.}, - // Expected PET - expected_pet_slopes[] = {0.1550, 0.1542, 0.1512, 0.1429, 0.1200}; + // Inputs + double const slopes[] = {0., 15., 34., 57., 90.}; + // Expected PET + double const expected_pet_slopes[] = { + 0.1550, 0.1542, 0.1512, 0.1429, 0.1200 + }; for (i = 0; i < 5; i++) { SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1160,13 +1229,12 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying aspect // [South facing slope = 0, East = -pi / 2, West = pi / 2, North = ±pi] - double - // Inputs - aspects[] = {-180, -90, -45, 0, 45, 90, 180}, - // Expected PET - expected_pet_aspects[] = { - 0.1357, 0.1549, 0.1681, 0.1736, 0.1681, 0.1549, 0.1357 - }; + // Inputs + double const aspects[] = {-180, -90, -45, 0, 45, 90, 180}; + // Expected PET + double const expected_pet_aspects[] = { + 0.1357, 0.1549, 0.1681, 0.1736, 0.1681, 0.1549, 0.1357 + }; for (i = 0; i < 7; i++) { SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1199,11 +1267,12 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying albedo [0-1] - double - // Inputs - reflecs[] = {0., 0.22, 0.46, 0.55, 1.}, - // Expected PET - expected_pet_reflecs[] = {0.1745, 0.1457, 0.1141, 0.1022, 0.0421}; + // Inputs + double const reflecs[] = {0., 0.22, 0.46, 0.55, 1.}; + // Expected PET + double const expected_pet_reflecs[] = { + 0.1745, 0.1457, 0.1141, 0.1022, 0.0421 + }; for (i = 0; i < 5; i++) { SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1237,11 +1306,10 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying relative humidity [0-100; %] - double - // Inputs - RHs[] = {0, 34, 56, 79, 100}, - // Expected PET - expected_pet_RHs[] = {0.2267, 0.2123, 0.1662, 0.1128, 0.0612}; + // Inputs + double const RHs[] = {0, 34, 56, 79, 100}; + // Expected PET + double const expected_pet_RHs[] = {0.2267, 0.2123, 0.1662, 0.1128, 0.0612}; for (i = 0; i < 5; i++) { SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1277,11 +1345,12 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying wind speed [m / s] - double - // Inputs - windsps[] = {0., 1., 5., 10., 20.}, - // Expected PET - expected_pet_windsps[] = {0.1016, 0.1426, 0.3070, 0.5124, 0.9232}; + // Inputs + double const windsps[] = {0., 1., 5., 10., 20.}; + // Expected PET + double const expected_pet_windsps[] = { + 0.1016, 0.1426, 0.3070, 0.5124, 0.9232 + }; SW_PET_init_run(&SW_AtmDemand); // Re-init radiation memoization @@ -1315,11 +1384,12 @@ TEST(AtmDemandTest, PETpetfunc) { // TEST `petfunc()` for varying cloud cover [0-100; %] - double - // Inputs - cloudcovs[] = {0, 12, 36, 76, 100}, - // Expected PET - expected_pet_cloudcovs[] = {0.1253, 0.1303, 0.1404, 0.1571, 0.1671}; + // Inputs + double cloudcovs[] = {0, 12, 36, 76, 100}; + // Expected PET + double const expected_pet_cloudcovs[] = { + 0.1253, 0.1303, 0.1404, 0.1571, 0.1671 + }; // Note: increasing cloud cover decreases H_gt and increases PET for (i = 0; i < 5; i++) { @@ -1374,24 +1444,46 @@ TEST(AtmDemandTest, PETPetfuncByTemps) { sw_init_logs(NULL, &LogInfo); - int doy, k1, k2, k3, k4, k5; - - unsigned int desc_rsds = 0; - - double pet, temp, RH, windspeed, cloudcover, fH_gt, - rsds = SW_MISSING, H_gt, H_oh, H_ot, H_gh, elev = 0., lat = 40., - slope = 0., aspect = SW_MISSING, reflec = 0.15; + int doy; + int k1; + int k2; + int k3; + int k4; + int k5; + + const unsigned int desc_rsds = 0; + + double pet; + double temp; + double RH; + double windspeed; + double cloudcover; + double fH_gt; + const double rsds = SW_MISSING; + double H_gt; + double H_oh; + double H_ot; + double H_gh; + const double elev = 0.; + const double lat = 40.; + const double slope = 0.; + const double aspect = SW_MISSING; + const double reflec = 0.15; FILE *fp; char fname[FILENAME_MAX]; - strcpy(fname, "Output/"); - strcat(fname, "Table__SW2_PET_Test__petfunc_by_temps.csv"); + (void) snprintf( + fname, + sizeof fname, + "%s", + "Output/Table__SW2_PET_Test__petfunc_by_temps.csv" + ); fp = OpenFile(fname, "w", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Column names - fprintf( + (void) fprintf( fp, "Temperature_C, RH_pct, windspeed_m_per_s, cloudcover_pct, fH_gt, " "PET_mm" @@ -1453,7 +1545,7 @@ TEST(AtmDemandTest, PETPetfuncByTemps) { sw_fail_on_error(&LogInfo); } - fprintf( + (void) fprintf( fp, "%f, %f, %f, %f, %f, %f\n", temp, @@ -1464,7 +1556,7 @@ TEST(AtmDemandTest, PETPetfuncByTemps) { pet ); - fflush(fp); + (void) fflush(fp); } } } diff --git a/tests/gtests/test_SW_Flow_lib_temp.cc b/tests/gtests/test_SW_Flow_lib_temp.cc index 0e12b7bb5..1ae97ad3f 100644 --- a/tests/gtests/test_SW_Flow_lib_temp.cc +++ b/tests/gtests/test_SW_Flow_lib_temp.cc @@ -1,4 +1,4 @@ -#include "include/generic.h" // for swFALSE, Bool, RealD, GT, fmax +#include "include/generic.h" // for swFALSE, Bool, GT, fmax #include "include/rands.h" // for RandNorm, RandSeed, RandUni... #include "include/SW_datastructs.h" // for LOG_INFO, ST_RGR_VALUES #include "include/SW_Defines.h" // for MAX_LAYERS, sw_random_t @@ -7,12 +7,10 @@ #include "tests/gtests/sw_testhelpers.h" // for length, missing #include "gmock/gmock.h" // for HasSubstr, MakePredicateFor... #include "gtest/gtest.h" // for Test, EXPECT_EQ, CmpHelperGT -#include // for fmaxf, ceil, fminf +#include // for fmax, ceil, fminf #include // for NULL -sw_random_t flowTemp_rng; - using ::testing::HasSubstr; namespace { @@ -20,7 +18,8 @@ namespace { TEST(SWFlowTempTest, SWFlowTempSurfaceTemperatureUnderSnow) { // declare inputs and output - double snow, airTempAvg; + double snow; + double airTempAvg; double tSoilAvg; // test when snow is 0 and airTempAvg > 0 @@ -68,18 +67,24 @@ TEST(SWFlowTempTest, SWFlowTempSoilTemperatureInit) { sw_init_logs(NULL, &LogInfo); // declare inputs and output - double deltaX = 15.0, theMaxDepth = 990.0, sTconst = 4.15, acc = 0.0; - unsigned int nlyrs, nRgr = 65; + double const deltaX = 15.0; + double const theMaxDepth = 990.0; + double const sTconst = 4.15; + double acc = 0.0; + unsigned int nlyrs; + unsigned int iStart; + unsigned int const nRgr = 65; Bool ptr_stError = swFALSE; sw_random_t STInit_rng; RandSeed(0u, 0u, &STInit_rng); // ***** Test when nlyrs = 1 ***** // - unsigned int i = 0.; + unsigned int i = 0; nlyrs = 1; - double width[] = {20}, sTempInit[] = {1}; - double bDensity[] = {RandNorm(1., 0.5, &STInit_rng)}, - fc[] = {RandNorm(1.5, 0.5, &STInit_rng)}; + double width[] = {20}; + double sTempInit[] = {1}; + double bDensity[] = {RandNorm(1., 0.5, &STInit_rng)}; + double fc[] = {RandNorm(1.5, 0.5, &STInit_rng)}; double wp[1]; wp[0] = fc[0] - 0.6; // wp will always be less than fc @@ -111,9 +116,8 @@ TEST(SWFlowTempTest, SWFlowTempSoilTemperatureInit) { sizeof(double) * MAX_ST_RGR * (MAX_LAYERS + 1) ); - for (unsigned int i = ceil(SW_Site.depths[nlyrs - 1] / deltaX); - i < nRgr + 1; - i++) { + iStart = (unsigned int) ceil(SW_Site.depths[nlyrs - 1] / deltaX); + for (i = iStart; i < nRgr + 1; i++) { EXPECT_EQ(SW_StRegValues.tlyrs_by_slyrs[i][nlyrs], -deltaX); // Values should be equal to -deltaX when i > the depth of the soil // profile/deltaX and j is == nlyrs @@ -175,9 +179,8 @@ TEST(SWFlowTempTest, SWFlowTempSoilTemperatureInit) { sizeof(double) * MAX_ST_RGR * (MAX_LAYERS + 1) ); - for (unsigned int i = ceil(SW_Site.depths[nlyrs - 1] / deltaX); - i < nRgr + 1; - i++) { + iStart = (unsigned int) ceil(SW_Site.depths[nlyrs - 1] / deltaX); + for (i = iStart; i < nRgr + 1; i++) { EXPECT_EQ(SW_StRegValues.tlyrs_by_slyrs[i][nlyrs], -deltaX); // Values should be equal to -deltaX when i > the depth of the soil // profile/deltaX and j is == nlyrs @@ -206,8 +209,12 @@ TEST(SWFlowTempTest, SWFlowTempSoilTemperatureInitDeathTest) { sw_init_logs(NULL, &LogInfo); // ***** Test when nlyrs = MAX_LAYERS (SW_Defines.h) ***** // - double deltaX = 15.0, sTconst = 4.15, acc = 0.0; - unsigned int nlyrs, nRgr = 65, i = 0.; + double const deltaX = 15.0; + double const sTconst = 4.15; + double acc = 0.0; + unsigned int nlyrs; + unsigned int const nRgr = 65; + unsigned int i = 0; Bool ptr_stError = swFALSE; nlyrs = MAX_LAYERS; double width2[] = {5, 5, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, @@ -230,7 +237,7 @@ TEST(SWFlowTempTest, SWFlowTempSoilTemperatureInitDeathTest) { /// test when theMaxDepth is less than soil layer depth - function should /// fail - double theMaxDepth2 = 70.0; + double const theMaxDepth2 = 70.0; // We expect an error when max depth < last layer soil_temperature_setup( @@ -275,19 +282,28 @@ TEST(SWFlowTempTest, SWFlowTempSoilLayerInterpolationFunctions) { sw_init_logs(NULL, &LogInfo); // declare inputs and output - double deltaX = 15.0, theMaxDepth = 990.0, sTconst = 4.15, acc = 0.0; - unsigned int nlyrs, nRgr = 65; + double const deltaX = 15.0; + double const theMaxDepth = 990.0; + double const sTconst = 4.15; + double acc = 0.0; + unsigned int nlyrs; + unsigned int iStart; + unsigned int const nRgr = 65; Bool ptr_stError = swFALSE; sw_random_t SLIF_rng; RandSeed(0u, 0u, &SLIF_rng); // ***** Test when nlyrs = 1 ***** // - unsigned int i = 0.; + unsigned int i = 0; nlyrs = 1; - double width[] = {20}, sTempInit[] = {1}; - double bDensity[] = {fmaxf(RandNorm(1.5, 0.5, &SLIF_rng), 0.1)}, - fc[] = {fmaxf(RandNorm(1.5, 0.5, &SLIF_rng), 0.1)}; + double tmp; + double width[] = {20}; + double sTempInit[] = {1}; + tmp = RandNorm(1.5, 0.5, &SLIF_rng); + double bDensity[] = {fmax(tmp, 0.1)}; + tmp = RandNorm(1.5, 0.5, &SLIF_rng); + double fc[] = {fmax(tmp, 0.1)}; double wp[1]; wp[0] = fmax(fc[0] - 0.6, .1); // wp will always be less than fc @@ -324,7 +340,8 @@ TEST(SWFlowTempTest, SWFlowTempSoilLayerInterpolationFunctions) { EXPECT_GT(SW_StRegValues.wpR[i], 0); } - for (i = ceil(SW_Site.depths[nlyrs - 1] / deltaX) + 1; i < nRgr + 1; i++) { + iStart = (unsigned int) ceil(SW_Site.depths[nlyrs - 1] / deltaX); + for (i = iStart; i < nRgr + 1; i++) { // The TempLayer values that are at depths greater than the max // SoilLayer depth should be uniform EXPECT_EQ(SW_StRegValues.bDensityR[i], SW_StRegValues.bDensityR[i - 1]); @@ -333,8 +350,9 @@ TEST(SWFlowTempTest, SWFlowTempSoilLayerInterpolationFunctions) { } // lyrSoil_to_lyrTemp_temperature tests - EXPECT_TRUE(missing(SW_StRegValues.oldavgLyrTempR[0]) - ); // surface temperature is initialized to missing because not used + // surface temperature is initialized to missing because not used + EXPECT_TRUE(missing(SW_StRegValues.oldavgLyrTempR[0])); + double maxvalR = 0.; for (i = 1; i < nRgr + 1; i++) { // Values interpolated into sTempInitR should be realistic @@ -367,9 +385,12 @@ TEST(SWFlowTempTest, SWFlowTempSoilLayerInterpolationFunctions) { double *wp2 = new double[nlyrs]; for (i = 0; i < nlyrs; i++) { - bDensity2[i] = fmaxf(RandNorm(1., 0.5, &SLIF_rng), 0.1); - fc2[i] = fmaxf(RandNorm(1.5, 0.5, &SLIF_rng), 0.1); - wp2[i] = fmaxf(fc2[i] - 0.6, 0.1); // wp will always be less than fc + // note: fmax() may be our macro that evaluates arguments twice + tmp = RandNorm(1., 0.5, &SLIF_rng); + bDensity2[i] = fmax(tmp, 0.1); + tmp = RandNorm(1.5, 0.5, &SLIF_rng); + fc2[i] = fmax(tmp, 0.1); + wp2[i] = fmax(fc2[i] - 0.6, 0.1); // wp will always be less than fc EXPECT_GT(bDensity2[i], 0); EXPECT_GT(fc2[i], 0); EXPECT_GT(wp2[i], 0); @@ -409,7 +430,8 @@ TEST(SWFlowTempTest, SWFlowTempSoilLayerInterpolationFunctions) { EXPECT_GT(SW_StRegValues.wpR[i], 0); } - for (i = ceil(SW_Site.depths[nlyrs - 1] / deltaX) + 1; i < nRgr + 1; i++) { + iStart = (unsigned int) ceil(SW_Site.depths[nlyrs - 1] / deltaX); + for (i = iStart; i < nRgr + 1; i++) { // The TempLayer values that are at depths greater than the max // SoilLayer depth should be uniform EXPECT_EQ(SW_StRegValues.bDensityR[i], SW_StRegValues.bDensityR[i - 1]); @@ -447,13 +469,16 @@ TEST(SWFlowTempTest, SWFlowTempSoilLayerInterpolationFunctions) { // Test set layer to frozen or unfrozen 'set_frozen_unfrozen' TEST(SWFlowTempTest, SWFlowTempSetFrozenUnfrozen) { - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; // declare inputs and output // ***** Test when nlyrs = 1 ***** // /// ***** Test that soil freezes ***** /// unsigned int nlyrs = 1; - double sTemp[] = {-5}, swc[] = {1.5}, swc_sat[] = {1.8}, width[] = {5}; + double sTemp[] = {-5}; + double swc[] = {1.5}; + double swc_sat[] = {1.8}; + double width[] = {5}; set_frozen_unfrozen(nlyrs, sTemp, swc, swc_sat, width, lyrFrozen); @@ -478,7 +503,7 @@ TEST(SWFlowTempTest, SWFlowTempSetFrozenUnfrozen) { double *swc2 = new double[nlyrs]; double *swc_sat2 = new double[nlyrs]; - unsigned int i = 0.; + unsigned int i = 0; for (i = 0; i < nlyrs; i++) { sTemp3[i] = -5; sTemp4[i] = 0; @@ -505,10 +530,17 @@ TEST(SWFlowTempTest, SWFlowTempSetFrozenUnfrozen) { TEST(SWFlowTempTest, SWFlowTempSoilTemperatureTodayFunction) { // declare inputs and output - double delta_time = 86400., deltaX = 15.0, T1 = 20.0, sTconst = 4.16, - csParam1 = 0.00070, csParam2 = 0.000030, shParam = 0.18, - surface_range = 1.; - unsigned int nRgr = 65, year = 1980, doy = 1; + double delta_time = 86400.; + double const deltaX = 15.0; + double const T1 = 20.0; + double const sTconst = 4.16; + double const csParam1 = 0.00070; + double const csParam2 = 0.000030; + double const shParam = 0.18; + double const surface_range = 1.; + unsigned int const nRgr = 65; + unsigned int const year = 1980; + unsigned int const doy = 1; Bool ptr_stError = swFALSE; sw_random_t STTF_rng; @@ -526,7 +558,7 @@ TEST(SWFlowTempTest, SWFlowTempSoilTemperatureTodayFunction) { double *bDensityR = new double[nRgr + 2]; double *temperatureRangeR = new double[nRgr + 2]; double *depthsR = new double[nRgr + 2]; - unsigned int i = 0.; + unsigned int i = 0; for (i = 0; i <= nRgr + 1; i++) { sTempR[i] = RandNorm(1.5, 1, &STTF_rng); sTempInitR[i] = RandNorm(1.5, 1, &STTF_rng); @@ -637,23 +669,46 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunction_Lyr01) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; - unsigned int k, year = 1980, doy = 1; + unsigned int k; + unsigned int const year = 1980; + unsigned int const doy = 1; // ***** Test when nlyrs = 1 ***** // - unsigned int nlyrs = 1, nRgr = 65; - double airTemp = 25.0, pet = 5.0, aet = 4.0, biomass = 100., - surfaceTemp = 15., bmLimiter = 300., t1Param1 = 15., t1Param2 = -4., - t1Param3 = 600., csParam1 = 0.00070, csParam2 = 0.00030, - shParam = 0.18, snowdepth = 5, sTconst = 4.15, deltaX = 15, - theMaxDepth = 990., snow = 1, max_air_temp = 10.1, - min_air_temp = -5.0, H_gt = 300.0, surface_max = 10.6, - surface_min = -6.8; + unsigned int const nlyrs = 1; + unsigned int const nRgr = 65; + double airTemp = 25.0; + double const pet = 5.0; + double const aet = 4.0; + double biomass = 100.; + double surfaceTemp = 15.; + double const bmLimiter = 300.; + double const t1Param1 = 15.; + double const t1Param2 = -4.; + double const t1Param3 = 600.; + double const csParam1 = 0.00070; + double const csParam2 = 0.00030; + double const shParam = 0.18; + double snowdepth = 5; + double const sTconst = 4.15; + double const deltaX = 15; + double const theMaxDepth = 990.; + double const snow = 1; + double const max_air_temp = 10.1; + double const min_air_temp = -5.0; + double const H_gt = 300.0; + double surface_max = 10.6; + double surface_min = -6.8; Bool ptr_stError = swFALSE; - double swc[] = {1.0}, swc_sat[] = {1.5}, bDensity[] = {1.8}, width[] = {20}, - sTemp[1], min_temp[] = {10.0}, max_temp[] = {1.0}; + double swc[] = {1.0}; + double swc_sat[] = {1.5}; + double bDensity[] = {1.8}; + double width[] = {20}; + double sTemp[1]; + double min_temp[] = {10.0}; + double max_temp[] = {1.0}; SW_Site.n_layers = nlyrs; SW_Site.stNRGR = nRgr; @@ -857,7 +912,7 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunction_Lyr01) { EXPECT_NE(surfaceTemp, surface_temperature_under_snow(airTemp, snow)); // checks for lyrTemp_to_lyrSoil_temperature - int resultValue = sizeof(sTemp) / sizeof(sTemp[0]); + int const resultValue = sizeof(sTemp) / sizeof(sTemp[0]); // when the number of soil layers is 1, sTemp should have length 1 EXPECT_EQ(1, resultValue); @@ -951,7 +1006,7 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunction_LyrMAX) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - RealD lyrFrozen[MAX_LAYERS] = {0}; + double lyrFrozen[MAX_LAYERS] = {0}; // ***** Test when nlyrs = MAX_LAYERS ***** // @@ -959,24 +1014,43 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunction_LyrMAX) { RandSeed(0u, 0u, &soilTemp_rng); - unsigned int i, k, year = 1980, doy = 1; + unsigned int i; + unsigned int k; + unsigned int const year = 1980; + unsigned int const doy = 1; // intialize values - unsigned int nRgr = 65; - double airTemp = 25.0, pet = 5.0, aet = 4.0, biomass = 100., - surfaceTemp = 15., bmLimiter = 300., t1Param1 = 15., t1Param2 = -4., - t1Param3 = 600., csParam1 = 0.00070, csParam2 = 0.00030, - shParam = 0.18, snowdepth = 5, sTconst = 4.15, deltaX = 15, - theMaxDepth = 990., snow = 1, max_air_temp = 10.1, - min_air_temp = -5.0, H_gt = 300.0, surface_max = 10.6, - surface_min = -6.8, acc = 0.; + unsigned int const nRgr = 65; + double const airTemp = 25.0; + double const pet = 5.0; + double const aet = 4.0; + double biomass = 100.; + double surfaceTemp = 15.; + double const bmLimiter = 300.; + double const t1Param1 = 15.; + double const t1Param2 = -4.; + double const t1Param3 = 600.; + double const csParam1 = 0.00070; + double const csParam2 = 0.00030; + double const shParam = 0.18; + double snowdepth = 5; + double const sTconst = 4.15; + double const deltaX = 15; + double const theMaxDepth = 990.; + double const snow = 1; + double const max_air_temp = 10.1; + double const min_air_temp = -5.0; + double const H_gt = 300.0; + double surface_max = 10.6; + double surface_min = -6.8; + double acc = 0.; Bool ptr_stError = swFALSE; - unsigned int nlyrs2 = MAX_LAYERS; + unsigned int const nlyrs2 = MAX_LAYERS; double width2[] = {5, 5, 5, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 20}; - double sTempInit3[] = {1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; + double const sTempInit3[] = {1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4}; double sTemp3[MAX_LAYERS]; double bDensity2[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; @@ -999,14 +1073,14 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunction_LyrMAX) { SW_Site.swcBulk_wiltpt[i] = 0.1 * width2[i]; // SWC(field capacity): width > swc_fc > swc_wp SW_Site.swcBulk_fieldcap[i] = - fminf(width2[i], SW_Site.swcBulk_wiltpt[i] + 0.15 * width2[i]); + fmin(width2[i], SW_Site.swcBulk_wiltpt[i] + 0.15 * width2[i]); // SWC(saturation): width > swc_sat > swc_fc SW_Site.swcBulk_saturated[i] = - fminf(width2[i], SW_Site.swcBulk_fieldcap[i] + 0.2 * width2[i]); + fmin(width2[i], SW_Site.swcBulk_fieldcap[i] + 0.2 * width2[i]); // SWC: swc_sat >= SWC > 0; here, swc_fc >= SWC >= swc_wp swc2[i] = RandUniFloatRange( - SW_Site.swcBulk_wiltpt[i], - SW_Site.swcBulk_fieldcap[i], + (float) SW_Site.swcBulk_wiltpt[i], + (float) SW_Site.swcBulk_fieldcap[i], &soilTemp_rng ); @@ -1216,7 +1290,7 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunction_LyrMAX) { EXPECT_NE(surfaceTemp, surface_temperature_under_snow(airTemp, snow)); // checks for lyrTemp_to_lyrSoil_temperature - int resultValue2 = sizeof(sTemp3) / sizeof(sTemp3[0]); + int const resultValue2 = sizeof(sTemp3) / sizeof(sTemp3[0]); // when the number of soil layers is MAX_LAYERS, length of sTemp3 should // be MAX_LAYERS @@ -1251,20 +1325,44 @@ TEST(SWFlowTempTest, SWFlowTempMainSoilTemperatureFunctionDeathTest) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - RealD lyrFrozen[MAX_LAYERS] = {0}, depths[MAX_LAYERS] = {0}; - - unsigned int nlyrs = 1, nRgr = 65, year = 1980, doy = 1; - double airTemp = 25.0, pet = 5.0, aet = 4.0, biomass = 100., - surfaceTemp = 15., bmLimiter = 300., t1Param1 = 15., t1Param2 = -4., - t1Param3 = 600., csParam1 = 0.00070, csParam2 = 0.00030, - shParam = 0.18, snowdepth = 5, sTconst = 4.15, deltaX = 15, - theMaxDepth = 990., snow = 1, max_air_temp = 10.1, - min_air_temp = -5.0, H_gt = 300.0, surface_max = 10.6, - surface_min = -6.8; + double lyrFrozen[MAX_LAYERS] = {0}; + double depths[MAX_LAYERS] = {0}; + + unsigned int const nlyrs = 1; + unsigned int const nRgr = 65; + unsigned int const year = 1980; + unsigned int const doy = 1; + double const airTemp = 25.0; + double const pet = 5.0; + double const aet = 4.0; + double const biomass = 100.; + double surfaceTemp = 15.; + double const bmLimiter = 300.; + double const t1Param1 = 15.; + double const t1Param2 = -4.; + double const t1Param3 = 600.; + double const csParam1 = 0.00070; + double const csParam2 = 0.00030; + double const shParam = 0.18; + double const snowdepth = 5; + double const sTconst = 4.15; + double const deltaX = 15; + double const theMaxDepth = 990.; + double const snow = 1; + double const max_air_temp = 10.1; + double const min_air_temp = -5.0; + double const H_gt = 300.0; + double surface_max = 10.6; + double surface_min = -6.8; Bool ptr_stError = swFALSE; - double swc[] = {1.0}, swc_sat[] = {1.5}, bDensity[] = {1.8}, width[] = {20}, - sTemp[1], min_temp[] = {10.0}, max_temp[] = {1.0}; + double swc[] = {1.0}; + double swc_sat[] = {1.5}; + double bDensity[] = {1.8}; + double width[] = {20}; + double sTemp[1]; + double min_temp[] = {10.0}; + double max_temp[] = {1.0}; // Should fail when soil_temperature was not initialized soil_temperature( diff --git a/tests/gtests/test_SW_Markov.cc b/tests/gtests/test_SW_Markov.cc index 9348e810c..b083bfcf7 100644 --- a/tests/gtests/test_SW_Markov.cc +++ b/tests/gtests/test_SW_Markov.cc @@ -1,4 +1,4 @@ -#include "include/generic.h" // for RealD, GT, fmin +#include "include/generic.h" // for GT, fmin #include "include/myMemory.h" // for Str_Dup #include "include/SW_datastructs.h" // for LOG_INFO, SW_MARKOV, SW_NFILES #include "include/SW_Defines.h" // for sw_random_t @@ -11,11 +11,14 @@ using ::testing::HasSubstr; -extern void (*test_mvnorm)(RealD *, RealD *, RealD, RealD, RealD, RealD, RealD, sw_random_t *, LOG_INFO *); +// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) +extern void (*test_mvnorm)(double *, double *, double, double, double, double, double, sw_random_t *, LOG_INFO *); extern void (*test_temp_correct_wetdry)( - RealD *, RealD *, RealD, RealD, RealD, RealD, RealD + double *, double *, double, double, double, double, double ); +// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + namespace { // Test the SW_MARKOV constructor 'SW_MKV_construct' TEST(WeatherGeneratorTest, WeatherGeneratorConstructor) { @@ -25,7 +28,7 @@ TEST(WeatherGeneratorTest, WeatherGeneratorConstructor) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - int rng_seed = 8; + int const rng_seed = 8; SW_MKV_init_ptrs(&SW_Markov); SW_MKV_construct(rng_seed, &SW_Markov); @@ -63,13 +66,20 @@ TEST(WeatherGeneratorTest, WeatherGeneratorRNGSeeding) { InFiles[eMarkovProb] = Str_Dup("Input/mkv_prob.in", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - int rng_seed, - // Turn on Markov weather generator - generateWeatherMethod = 2; + int rng_seed; + // Turn on Markov weather generator + unsigned int const generateWeatherMethod = 2; - short k, n = 18, seed = 42, year = 1980; - RealD tmax, tmin, ppt; - RealD *tmax0 = new double[n], *tmin0 = new double[n], *ppt0 = new double[n]; + short k; + short const n = 18; + short const seed = 42; + short const year = 1980; + double tmax; + double tmin; + double ppt; + double *tmax0 = new double[n]; + double *tmin0 = new double[n]; + double *ppt0 = new double[n]; //--- Generate some weather values with fixed seed ------ @@ -162,9 +172,12 @@ TEST(WeatherGeneratorTest, WeatherGeneratormvnorm) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - int rng_seed = 9; - short k, n = 3; - RealD tmax = 0., tmin = 0., tval; + int const rng_seed = 9; + short k; + short const n = 3; + double tmax = 0.; + double tmin = 0.; + double tval; SW_MKV_init_ptrs(&SW_Markov); SW_MKV_construct(rng_seed, &SW_Markov); // initialize markov_rng @@ -249,8 +262,9 @@ TEST(WeatherGeneratorTest, WeatherGeneratormvnormDeathTest) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - int rng_seed = 11; - RealD tmax = 0., tmin = 0.; + int const rng_seed = 11; + double tmax = 0.; + double tmin = 0.; SW_MKV_init_ptrs(&SW_Markov); SW_MKV_construct(rng_seed, &SW_Markov); // initialize markov_rng @@ -276,9 +290,16 @@ TEST(WeatherGeneratorTest, WeatherGeneratorWetDryTemperatureCorrection) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - int rng_seed = 13; - RealD tmax = 0., tmin = 0., t0 = 0., t10 = 10., wet = 1., dry = 0., - cf0 = 0., cf_pos = 5., cf_neg = -5.; + int const rng_seed = 13; + double tmax = 0.; + double tmin = 0.; + double const t0 = 0.; + double const t10 = 10.; + double const wet = 1.; + double const dry = 0.; + double const cf0 = 0.; + double const cf_pos = 5.; + double const cf_neg = -5.; SW_MKV_init_ptrs(&SW_Markov); SW_MKV_construct(rng_seed, &SW_Markov); // initialize markov_rng diff --git a/tests/gtests/test_SW_Site.cc b/tests/gtests/test_SW_Site.cc index 8fbea3360..c42b86a3b 100644 --- a/tests/gtests/test_SW_Site.cc +++ b/tests/gtests/test_SW_Site.cc @@ -1,4 +1,4 @@ -#include "include/generic.h" // for RealD, Bool, swFALSE +#include "include/generic.h" // for Bool, swFALSE #include "include/SW_datastructs.h" // for LOG_INFO #include "include/SW_Defines.h" // for SWRC_PARAM_NMAX, SW_MISSING #include "include/SW_Main_lib.h" // for sw_fail_on_error, sw_init_logs @@ -13,21 +13,21 @@ using ::testing::HasSubstr; namespace { // List SWRC Campbell1974: all PTFs -const char *ns_ptfca2C1974[] = { +const char *const ns_ptfca2C1974[] = { "Campbell1974", "Cosby1984AndOthers", "Cosby1984" }; // List SWRC vanGenuchten1980: all PTFs -const char *ns_ptfa2vG1980[] = {"vanGenuchten1980", "Rosetta3"}; +const char *const ns_ptfa2vG1980[] = {"vanGenuchten1980", "Rosetta3"}; // List SWRC vanGenuchten1980: PTFs implemented in SOILWAT2 -const char *ns_ptfc2vG1980[] = {"vanGenuchten1980"}; +const char *const ns_ptfc2vG1980[] = {"vanGenuchten1980"}; // List SWRC FXW: all PTFs -const char *ns_ptfa2FXW[] = {"FXW", "neuroFX2021"}; +const char *const ns_ptfa2FXW[] = {"FXW", "neuroFX2021"}; // List SWRC FXW: PTFs implemented in SOILWAT2 -const char *ns_ptfc2FXW[] = {"FXW"}; +const char *const ns_ptfc2FXW[] = {"FXW"}; // Test pedotransfer functions TEST(SiteTest, SitePTFs) { @@ -36,9 +36,13 @@ TEST(SiteTest, SitePTFs) { sw_init_logs(NULL, &LogInfo); // inputs - RealD swrcp[SWRC_PARAM_NMAX]; - RealD sand = 0.33, clay = 0.33, gravel = 0.1, bdensity = 1.4; - unsigned int swrc_type, k; + double swrcp[SWRC_PARAM_NMAX]; + double const sand = 0.33; + double const clay = 0.33; + double const gravel = 0.1; + double const bdensity = 1.4; + unsigned int swrc_type; + unsigned int k; //--- Matching PTF-SWRC pairs @@ -108,8 +112,11 @@ TEST(SiteTest, SitePTFsDeathTest) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - RealD swrcp[SWRC_PARAM_NMAX]; - RealD sand = 0.33, clay = 0.33, gravel = 0.1, bdensity = 1.4; + double swrcp[SWRC_PARAM_NMAX]; + double const sand = 0.33; + double const clay = 0.33; + double const gravel = 0.1; + double const bdensity = 1.4; unsigned int ptf_type; @@ -191,7 +198,7 @@ TEST(SiteTest, SiteSWRCpChecksDeathTest) { sw_init_logs(NULL, &LogInfo); // inputs - RealD swrcp[SWRC_PARAM_NMAX]; + double swrcp[SWRC_PARAM_NMAX]; unsigned int swrc_type; @@ -212,14 +219,15 @@ TEST(SiteTest, SiteSWRCpChecks) { sw_init_logs(NULL, &LogInfo); // inputs - RealD swrcp[SWRC_PARAM_NMAX], tmp; + double swrcp[SWRC_PARAM_NMAX]; + double tmp; unsigned int swrc_type; //--- SWRC: Campbell1974 swrc_type = encode_str2swrc((char *) "Campbell1974", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - memset(swrcp, 0., SWRC_PARAM_NMAX * sizeof(swrcp[0])); + memset(swrcp, 0, SWRC_PARAM_NMAX * sizeof(swrcp[0])); swrcp[0] = 24.2159; swrcp[1] = 0.4436; swrcp[2] = 10.3860; @@ -255,7 +263,7 @@ TEST(SiteTest, SiteSWRCpChecks) { //--- Fail SWRC: vanGenuchten1980 swrc_type = encode_str2swrc((char *) "vanGenuchten1980", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - memset(swrcp, 0., SWRC_PARAM_NMAX * sizeof(swrcp[0])); + memset(swrcp, 0, SWRC_PARAM_NMAX * sizeof(swrcp[0])); swrcp[0] = 0.1246; swrcp[1] = 0.4445; swrcp[2] = 0.0112; @@ -306,7 +314,7 @@ TEST(SiteTest, SiteSWRCpChecks) { //--- Fail SWRC: FXW swrc_type = encode_str2swrc((char *) "FXW", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - memset(swrcp, 0., SWRC_PARAM_NMAX * sizeof(swrcp[0])); + memset(swrcp, 0, SWRC_PARAM_NMAX * sizeof(swrcp[0])); swrcp[0] = 0.437461; swrcp[1] = 0.050757; swrcp[2] = 1.247689; @@ -370,8 +378,13 @@ TEST(SiteTest, SitePTFRawlsBrakensiek1985) { sw_init_logs(NULL, &LogInfo); // declare mock INPUTS - double theta_min, clay = 0.1, sand = 0.6, porosity = 0.4; - int k1, k2, k3; + double theta_min; + double clay = 0.1; + double sand = 0.6; + double porosity = 0.4; + int k1; + int k2; + int k3; //--- EXPECT SW_MISSING if soil texture is out of range // within range: sand [0.05, 0.7], clay [0.05, 0.6], porosity [0.1, 1[ @@ -464,31 +477,34 @@ TEST_F(SiteFixtureTest, SiteSoilTranspirationParametersDeathTest) { TEST_F(SiteFixtureTest, SiteSoilTranspirationRegions) { /* Notes: - SW_Site.n_layers is base1 - - soil layer information in _TranspRgnBounds is base0 + - soil layer information in TranspRgnBounds is base0 */ - LyrIndex i, id, nRegions, prev_TranspRgnBounds[MAX_TRANSP_REGIONS] = {0}; - RealD soildepth; + LyrIndex i; + LyrIndex id; + LyrIndex nRegions; + LyrIndex prevTranspRgnBounds[MAX_TRANSP_REGIONS] = {0}; + double soildepth; for (i = 0; i < MAX_TRANSP_REGIONS; ++i) { - prev_TranspRgnBounds[i] = SW_Run.Site._TranspRgnBounds[i]; + prevTranspRgnBounds[i] = SW_Run.Site.TranspRgnBounds[i]; } // Check that "default" values do not change region bounds nRegions = 3; - RealD regionLowerBounds1[] = {20., 40., 100.}; + double regionLowerBounds1[] = {20., 40., 100.}; derive_soilRegions(&SW_Run.Site, nRegions, regionLowerBounds1, &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error for (i = 0; i < nRegions; ++i) { // Quickly calculate soil depth for current region as output information soildepth = 0.; - for (id = 0; id <= SW_Run.Site._TranspRgnBounds[i]; ++id) { + for (id = 0; id <= SW_Run.Site.TranspRgnBounds[i]; ++id) { soildepth += SW_Run.Site.width[id]; } - EXPECT_EQ(prev_TranspRgnBounds[i], SW_Run.Site._TranspRgnBounds[i]) + EXPECT_EQ(prevTranspRgnBounds[i], SW_Run.Site.TranspRgnBounds[i]) << "for transpiration region = " << i + 1 << " at a soil depth of " << soildepth << " cm"; } @@ -496,32 +512,32 @@ TEST_F(SiteFixtureTest, SiteSoilTranspirationRegions) { // Check that setting one region for all soil layers works nRegions = 1; - RealD regionLowerBounds2[] = {100.}; + double regionLowerBounds2[] = {100.}; derive_soilRegions(&SW_Run.Site, nRegions, regionLowerBounds2, &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error for (i = 0; i < nRegions; ++i) { - EXPECT_EQ(SW_Run.Site.n_layers - 1, SW_Run.Site._TranspRgnBounds[i]) + EXPECT_EQ(SW_Run.Site.n_layers - 1, SW_Run.Site.TranspRgnBounds[i]) << "for a single transpiration region across all soil layers"; } // Check that setting one region for one soil layer works nRegions = 1; - RealD regionLowerBounds3[] = {SW_Run.Site.width[0]}; + double regionLowerBounds3[] = {SW_Run.Site.width[0]}; derive_soilRegions(&SW_Run.Site, nRegions, regionLowerBounds3, &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error for (i = 0; i < nRegions; ++i) { EXPECT_EQ( - 0, SW_Run.Site._TranspRgnBounds[i] + 0, SW_Run.Site.TranspRgnBounds[i] ) << "for a single transpiration region for the shallowest soil layer"; } // Check that setting the maximal number of regions works nRegions = MAX_TRANSP_REGIONS; - RealD *regionLowerBounds4 = new RealD[nRegions]; + double *regionLowerBounds4 = new double[nRegions]; // Example: one region each for the topmost soil layers soildepth = 0.; for (i = 0; i < nRegions; ++i) { @@ -532,7 +548,7 @@ TEST_F(SiteFixtureTest, SiteSoilTranspirationRegions) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error for (i = 0; i < nRegions; ++i) { - EXPECT_EQ(i, SW_Run.Site._TranspRgnBounds[i]) + EXPECT_EQ(i, SW_Run.Site.TranspRgnBounds[i]) << "for transpiration region for the " << i + 1 << "-th soil layer"; } @@ -545,7 +561,8 @@ TEST(SiteTest, SiteSoilDensity) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - double soildensity = 1.4, fcoarse = 0.1; + double const soildensity = 1.4; + double const fcoarse = 0.1; // Check that matric density is zero if coarse fragments is 100% @@ -586,7 +603,7 @@ TEST(SiteTest, SiteSoilDensity) { } TEST_F(SiteFixtureTest, SiteSoilDensityTypes) { - double fcoarse = 0.1; + double const fcoarse = 0.1; // Inputs represent matric density SW_Run.Site.type_soilDensityInput = SW_MATRIC; diff --git a/tests/gtests/test_SW_SoilWater.cc b/tests/gtests/test_SW_SoilWater.cc index ee93359dd..11d95bc5d 100644 --- a/tests/gtests/test_SW_SoilWater.cc +++ b/tests/gtests/test_SW_SoilWater.cc @@ -1,4 +1,4 @@ -#include "include/generic.h" // for RealD, LOGERROR, LOGWARN +#include "include/generic.h" // for LOGERROR, LOGWARN #include "include/SW_datastructs.h" // for LOG_INFO, SW_SITE #include "include/SW_Defines.h" // for SW_MISSING, SWRC_PARAM_NMAX #include "include/SW_Main_lib.h" // for sw_fail_on_error, sw_init_logs @@ -19,8 +19,15 @@ namespace { TEST(SoilWaterTest, SoilWaterSWCadjustSnow) { // setup variables - RealD doy = 1, temp_min = 0, temp_max = 10, ppt = 1, rain = 1.5, snow = 1.5, - snowmelt = 1.2, temp_snow = 0, snowpack[TWO_DAYS] = {0}; + const unsigned int doy = 1; + double const temp_min = 0; + double const temp_max = 10; + double const ppt = 1; + double rain = 1.5; + double snow = 1.5; + double snowmelt = 1.2; + double temp_snow = 0; + double snowpack[TWO_DAYS] = {0}; SW_SITE SW_Site; @@ -80,8 +87,15 @@ TEST(SoilWaterTest, SoilWaterSWCadjustSnow) { } TEST(SoilWaterTest, SoilWaterSWCadjustSnow2) { - RealD doy = 1, temp_min = 0, temp_max = 22, ppt = 1, rain = 1.5, snow = 1.5, - snowmelt = 1.2, temp_snow = 0, snowpack[TWO_DAYS] = {0}; + const unsigned int doy = 1; + double const temp_min = 0; + double const temp_max = 22; + double const ppt = 1; + double rain = 1.5; + double snow = 1.5; + double snowmelt = 1.2; + double temp_snow = 0; + double snowpack[TWO_DAYS] = {0}; SW_SITE SW_Site; @@ -122,30 +136,42 @@ TEST(SoilWaterTest, SoilWaterTranslateBetweenSWCandSWP) { sw_init_logs(NULL, &LogInfo); // set up mock variables - unsigned int swrc_type, ptf_type, k; + unsigned int swrc_type; + unsigned int ptf_type; + unsigned int k; const int em = LOGERROR; - RealD phi, swcBulk, swc_sat, swc_fc, swc_wp, swp, swrcp[SWRC_PARAM_NMAX]; - RealD sand = 0.33, clay = 0.33, gravel = 0.2, bdensity = 1.4, width = 10.; + double phi; + double swcBulk; + double swc_sat; + double swc_fc; + double swc_wp; + double swp; + double swrcp[SWRC_PARAM_NMAX]; + double const sand = 0.33; + double const clay = 0.33; + double const gravel = 0.2; + double const bdensity = 1.4; + double const width = 10.; // SWP values in [0, Inf[ but FXW maxes out at 6178.19079 bar - RealD swpsb[12] = { + double const swpsb[12] = { 0., 0.001, 0.01, 0.026, 0.027, 0.33, 15., 30., 100., 300., 1000., 6178. }; // SWP values in [fc, Inf[ but FXW maxes out at 6178.19079 bar - RealD swpsi[7] = {0.33, 15., 30., 100., 300., 1000., 6178.}; + double const swpsi[7] = {0.33, 15., 30., 100., 300., 1000., 6178.}; std::ostringstream msg; // Loop over SWRCs for (swrc_type = 0; swrc_type < N_SWRCs; swrc_type++) { - memset(swrcp, 0., SWRC_PARAM_NMAX * sizeof(swrcp[0])); + memset(swrcp, 0, SWRC_PARAM_NMAX * sizeof(swrcp[0])); // Find a suitable PTF to generate `SWRCp` for (ptf_type = 0; ptf_type < N_PTFs && - !check_SWRC_vs_PTF( - (char *) swrc2str[swrc_type], (char *) ptf2str[ptf_type] - ); + (check_SWRC_vs_PTF( + (char *) swrc2str[swrc_type], (char *) ptf2str[ptf_type] + ) == 0u); ptf_type++) { } @@ -341,7 +367,9 @@ TEST(SoilWaterTest, SoilWaterSWCtoSWPDeathTest) { sw_init_logs(NULL, &LogInfo); // set up mock variables - RealD swrcp[SWRC_PARAM_NMAX], gravel = 0.1, width = 10.; + double swrcp[SWRC_PARAM_NMAX]; + double const gravel = 0.1; + double const width = 10.; unsigned int swrc_type; @@ -426,7 +454,7 @@ TEST(SoilWaterTest, SoilWaterSWCtoSWPDeathTest) { swrc_type = encode_str2swrc((char *) "vanGenuchten1980", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - memset(swrcp, 0., SWRC_PARAM_NMAX * sizeof(swrcp[0])); + memset(swrcp, 0, SWRC_PARAM_NMAX * sizeof(swrcp[0])); swrcp[0] = 0.1246; swrcp[1] = 0.4445; swrcp[2] = 0.0112; @@ -458,7 +486,9 @@ TEST(SoilWaterTest, SoilWaterSWPtoSWCDeathTest) { sw_init_logs(NULL, &LogInfo); // set up mock variables - RealD swrcp[SWRC_PARAM_NMAX], gravel = 0.1, width = 10.; + double swrcp[SWRC_PARAM_NMAX]; + double const gravel = 0.1; + double const width = 10.; unsigned int swrc_type; diff --git a/tests/gtests/test_SW_SpinUp.cc b/tests/gtests/test_SW_SpinUp.cc index b00aac8f0..6ec38712f 100644 --- a/tests/gtests/test_SW_SpinUp.cc +++ b/tests/gtests/test_SW_SpinUp.cc @@ -1,8 +1,8 @@ -#include "include/generic.h" // for RealD, swTRUE +#include "include/generic.h" // for swTRUE #include "include/SW_Control.h" // for SW_CTL_main, SW_CTL_run_spinup #include "include/SW_Main_lib.h" // for sw_fail_on_error #include "include/SW_Times.h" // for Today -#include "tests/gtests/sw_testhelpers.h" // for SpinUpTest +#include "tests/gtests/sw_testhelpers.h" // for SpinUpFixtureTest #include "gtest/gtest.h" // for Test, Message, TestPartResul... #if defined(SW2_SpinupEvaluation) @@ -10,16 +10,17 @@ #include "include/SW_datastructs.h" // for SW_RUN, LOG_INFO #include "include/SW_Site.h" // for SW_SIT_init_run #include "include/SW_SoilWater.h" // for SW_SWC_init_run -#include // for fprintf, fflush, FILE -#include // for strcat, strcpy +#include // for fprintf, fflush, snprintf #endif namespace { // Test SpinUp with mode = 1 and scope > duration -TEST_F(SpinUpTest, Mode1WithScopeGreaterThanDuration) { - int i, n = 4; // n = number of soil layers to test - RealD *prevTemp = new double[n], *prevMoist = new double[n]; +TEST_F(SpinUpFixtureTest, Mode1WithScopeGreaterThanDuration) { + int i; + int const n = 4; // n = number of soil layers to test + double *prevTemp = new double[n]; + double *prevMoist = new double[n]; SW_Run.Model.SW_SpinUp.mode = 1; SW_Run.Model.SW_SpinUp.scope = 27; @@ -63,9 +64,11 @@ TEST_F(SpinUpTest, Mode1WithScopeGreaterThanDuration) { } // Test SpinUp with mode = 1 and scope = duration -TEST_F(SpinUpTest, Mode1WithScopeEqualToDuration) { - int i, n = 4; // n = number of soil layers to test - RealD *prevTemp = new double[n], *prevMoist = new double[n]; +TEST_F(SpinUpFixtureTest, Mode1WithScopeEqualToDuration) { + int i; + int const n = 4; // n = number of soil layers to test + double *prevTemp = new double[n]; + double *prevMoist = new double[n]; SW_Run.Model.SW_SpinUp.mode = 1; SW_Run.Model.SW_SpinUp.scope = 3; @@ -109,9 +112,11 @@ TEST_F(SpinUpTest, Mode1WithScopeEqualToDuration) { } // Test SpinUp with mode = 1 and scope < duration -TEST_F(SpinUpTest, Mode1WithScopeLessThanDuration) { - int i, n = 4; // n = number of soil layers to test - RealD *prevTemp = new double[n], *prevMoist = new double[n]; +TEST_F(SpinUpFixtureTest, Mode1WithScopeLessThanDuration) { + int i; + int const n = 4; // n = number of soil layers to test + double *prevTemp = new double[n]; + double *prevMoist = new double[n]; SW_Run.Model.SW_SpinUp.mode = 1; SW_Run.Model.SW_SpinUp.scope = 1; @@ -155,9 +160,11 @@ TEST_F(SpinUpTest, Mode1WithScopeLessThanDuration) { } // Test SpinUp with mode = 2 and scope > duration -TEST_F(SpinUpTest, Mode2WithScopeGreaterThanDuration) { - int i, n = 4; // n = number of soil layers to test - RealD *prevTemp = new double[n], *prevMoist = new double[n]; +TEST_F(SpinUpFixtureTest, Mode2WithScopeGreaterThanDuration) { + int i; + int const n = 4; // n = number of soil layers to test + double *prevTemp = new double[n]; + double *prevMoist = new double[n]; SW_Run.Model.SW_SpinUp.mode = 2; SW_Run.Model.SW_SpinUp.scope = 27; @@ -201,9 +208,11 @@ TEST_F(SpinUpTest, Mode2WithScopeGreaterThanDuration) { } // Test SpinUp with mode = 2 and scope = duration -TEST_F(SpinUpTest, Mode2WithScopeEqualToDuration) { - int i, n = 4; // n = number of soil layers to test - RealD *prevTemp = new double[n], *prevMoist = new double[n]; +TEST_F(SpinUpFixtureTest, Mode2WithScopeEqualToDuration) { + int i; + int const n = 4; // n = number of soil layers to test + double *prevTemp = new double[n]; + double *prevMoist = new double[n]; SW_Run.Model.SW_SpinUp.mode = 2; SW_Run.Model.SW_SpinUp.scope = 3; @@ -247,9 +256,11 @@ TEST_F(SpinUpTest, Mode2WithScopeEqualToDuration) { } // Test SpinUp with mode = 2 and scope < duration -TEST_F(SpinUpTest, Mode2WithScopeLessThanDuration) { - int i, n = 4; // n = number of soil layers to test - RealD *prevTemp = new double[n], *prevMoist = new double[n]; +TEST_F(SpinUpFixtureTest, Mode2WithScopeLessThanDuration) { + int i; + int const n = 4; // n = number of soil layers to test + double *prevTemp = new double[n]; + double *prevMoist = new double[n]; SW_Run.Model.SW_SpinUp.mode = 2; SW_Run.Model.SW_SpinUp.scope = 1; @@ -306,16 +317,20 @@ TEST_F(SpinUpTest, Mode2WithScopeLessThanDuration) { // Rscript tools/plot__SW2_SpinupEvaluation.R // ``` -TEST_F(SpinUpTest, SpinupEvaluation) { +TEST_F(SpinUpFixtureTest, SpinupEvaluation) { SW_RUN local_sw; LOG_INFO local_LogInfo; FILE *fp; char fname[FILENAME_MAX]; - int i, n = 8, // n = number of soil layers to test - k1, test_duration[6] = {0, 1, 3, 5, 10, 20}, k2, k3; - float test_swcInit[4] = {0.5, 1, 15, 45}; - float test_tsInit[5][8] = { + int i; + const int n = 8; // n = number of soil layers to test + int k1; + int k2; + int k3; + const int test_duration[6] = {0, 1, 3, 5, 10, 20}; + const double test_swcInit[4] = {0.5, 1, 15, 45}; + const double test_tsInit[5][8] = { {-2, -2, -2, -2, -2, -2, -2, -2}, {0, 0, 0, 0, 0, 0, 0, 0}, {-1, -1, -1, -1, 0, 0, 1, 1}, @@ -325,14 +340,19 @@ TEST_F(SpinUpTest, SpinupEvaluation) { // Output file - strcpy(fname, SW_Domain.PathInfo.output_prefix); - strcat(fname, "Table__SW2_SpinupEvaluation.csv"); + (void) snprintf( + fname, + sizeof fname, + "%s%s", + SW_Domain.PathInfo.output_prefix, + "Table__SW2_SpinupEvaluation.csv" + ); fp = OpenFile(fname, "w", &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Column names - fprintf( + (void) fprintf( fp, "stage,spinup_duration,swc_init,ts_init,variable,soil_layer,value" "\n" @@ -347,7 +367,9 @@ TEST_F(SpinUpTest, SpinupEvaluation) { sw_init_logs(NULL, &local_LogInfo); // deep copy of template - SW_RUN_deepCopy(&SW_Run, &local_sw, &local_LogInfo); + SW_RUN_deepCopy( + &SW_Run, &local_sw, &SW_Domain.OutDom, &local_LogInfo + ); // exit test program if unexpected error sw_fail_on_error(&local_LogInfo); @@ -360,7 +382,7 @@ TEST_F(SpinUpTest, SpinupEvaluation) { //--- k2: set initial swc values - local_sw.Site._SWCInitVal = test_swcInit[k2]; + local_sw.Site.SWCInitVal = test_swcInit[k2]; SW_SIT_init_run( &local_sw.VegProd, &local_sw.Site, &local_LogInfo ); @@ -382,7 +404,7 @@ TEST_F(SpinUpTest, SpinupEvaluation) { // Print initial values for (i = 0; i < n; i++) { - fprintf( + (void) fprintf( fp, "init,%d,%f,%d,swc,%d,%f\n" "init,%d,%f,%d,ts,%d,%f\n", @@ -398,17 +420,19 @@ TEST_F(SpinUpTest, SpinupEvaluation) { local_sw.Site.avgLyrTempInit[i] ); } - fflush(fp); + (void) fflush(fp); // Run the spinup if (test_duration[k1] > 0) { - SW_CTL_run_spinup(&local_sw, &local_LogInfo); + SW_CTL_run_spinup( + &local_sw, &SW_Domain.OutDom, &local_LogInfo + ); sw_fail_on_error(&local_LogInfo); // Print values after spinup for (i = 0; i < n; i++) { - fprintf( + (void) fprintf( fp, "spinup,%d,%f,%d,swc,%d,%f\n" "spinup,%d,%f,%d,ts,%d,%f\n", @@ -424,7 +448,7 @@ TEST_F(SpinUpTest, SpinupEvaluation) { local_sw.SoilWat.avgLyrTemp[i] ); } - fflush(fp); + (void) fflush(fp); } @@ -437,7 +461,7 @@ TEST_F(SpinUpTest, SpinupEvaluation) { // Print values after simulation for (i = 0; i < n; i++) { - fprintf( + (void) fprintf( fp, "srun,%d,%f,%d,swc,%d,%f\n" "srun,%d,%f,%d,ts,%d,%f\n", @@ -453,7 +477,7 @@ TEST_F(SpinUpTest, SpinupEvaluation) { local_sw.SoilWat.avgLyrTemp[i] ); } - fflush(fp); + (void) fflush(fp); } // end of loop over test_tsInit } // end of loop over test_swcInit diff --git a/tests/gtests/test_SW_VegEstab.cc b/tests/gtests/test_SW_VegEstab.cc index 6954778f6..71567ac52 100644 --- a/tests/gtests/test_SW_VegEstab.cc +++ b/tests/gtests/test_SW_VegEstab.cc @@ -14,7 +14,7 @@ TEST_F(VegEstabFixtureTest, SimulateWithVegEstab) { swTRUE, swFALSE, SW_Domain.PathInfo.InFiles, - SW_Domain.PathInfo._ProjDir, + SW_Domain.PathInfo.SW_ProjDir, &LogInfo ); diff --git a/tests/gtests/test_SW_VegProd.cc b/tests/gtests/test_SW_VegProd.cc index 78d4e975e..8502ae4f4 100644 --- a/tests/gtests/test_SW_VegProd.cc +++ b/tests/gtests/test_SW_VegProd.cc @@ -10,55 +10,33 @@ using ::testing::HasSubstr; - -static void assert_decreasing_SWPcrit(SW_VEGPROD *SW_VegProd); - -static void assert_decreasing_SWPcrit(SW_VEGPROD *SW_VegProd) { - int rank, vegtype; - - for (rank = 0; rank < NVEGTYPES - 1; rank++) { - vegtype = SW_VegProd->rank_SWPcrits[rank]; - - /* - sw_printf("Rank=%d is vegtype=%d with SWPcrit=%f\n", - rank, vegtype, - SW_VegProd.critSoilWater[vegtype]); - */ - - // Check that SWPcrit of `vegtype` is larger or equal to - // SWPcrit of the vegetation type with the next larger rank - ASSERT_GE( - SW_VegProd->critSoilWater[vegtype], - SW_VegProd->critSoilWater[SW_VegProd->rank_SWPcrits[rank + 1]] - ); - } -} +namespace { // Vegetation cover: see `estimatePotNatVegComposition()` // RelAbundanceL0 and inputValues indices -int succIndex = 0; -int forbIndex = 1; -int C3Index = 2; -int C4Index = 3; -int grassAnn = 4; -int shrubIndex = 5; -int treeIndex = 6; -int bareGround = 7; +const int succIndex = 0; +const int forbIndex = 1; +const int C3Index = 2; +const int C4Index = 3; +const int grassAnn = 4; +const int shrubIndex = 5; +const int treeIndex = 6; +const int bareGround = 7; // RelAbundanceL1 indices -int treeIndexL1 = 0; -int shrubIndexL1 = 1; -int forbIndexL1 = 2; -int grassesIndexL1 = 3; -int bareGroundL1 = 4; +const int treeIndexL1 = 0; +const int shrubIndexL1 = 1; +const int forbIndexL1 = 2; +const int grassesIndexL1 = 3; +const int bareGroundL1 = 4; -static void copyL0(double outL0[], double inL0[]) { +void copyL0(double outL0[], const double inL0[]) { for (int index = 0; index < 8; index++) { outL0[index] = inL0[index]; } } -static void calcVegCoverL1FromL0(double L1[], double L0[]) { +void calcVegCoverL1FromL0(double L1[], const double L0[]) { L1[treeIndexL1] = L0[treeIndex]; L1[shrubIndexL1] = L0[shrubIndex]; L1[forbIndexL1] = L0[forbIndex] + L0[succIndex]; @@ -66,8 +44,8 @@ static void calcVegCoverL1FromL0(double L1[], double L0[]) { L1[bareGroundL1] = L0[bareGround]; } -static void calcGrassCoverFromL0(double grass[], double L0[]) { - double grass_sum = L0[C3Index] + L0[C4Index] + L0[grassAnn]; +void calcGrassCoverFromL0(double grass[], const double L0[]) { + double const grass_sum = L0[C3Index] + L0[C4Index] + L0[grassAnn]; if (GT(grass_sum, 0.)) { grass[0] = L0[C3Index] / grass_sum; @@ -80,8 +58,27 @@ static void calcGrassCoverFromL0(double grass[], double L0[]) { } } -namespace { -int k; +void assert_decreasing_SWPcrit(SW_VEGPROD *SW_VegProd) { + int rank; + int vegtype; + + for (rank = 0; rank < NVEGTYPES - 1; rank++) { + vegtype = SW_VegProd->rank_SWPcrits[rank]; + + /* + sw_printf("Rank=%d is vegtype=%d with SWPcrit=%f\n", + rank, vegtype, + SW_VegProd.critSoilWater[vegtype]); + */ + + // Check that SWPcrit of `vegtype` is larger or equal to + // SWPcrit of the vegetation type with the next larger rank + ASSERT_GE( + SW_VegProd->critSoilWater[vegtype], + SW_VegProd->critSoilWater[SW_VegProd->rank_SWPcrits[rank + 1]] + ); + } +} // Test the SW_VEGPROD constructor 'SW_VPD_construct' TEST_F(VegProdFixtureTest, VegProdConstructor) { @@ -96,6 +93,7 @@ TEST_F(VegProdFixtureTest, VegProdConstructor) { // would see only NULL and thus not de-allocate the required second time // to avoid a leak) SW_VEGPROD SW_VegProd; + int k; SW_VPD_construct(&SW_VegProd); // allocate memory for output pointers @@ -123,8 +121,9 @@ TEST_F(VegProdFixtureTest, VegProdConstructor) { // Test the application of the biomass CO2-effect TEST(VegProdTest, VegProdBiomassCO2effect) { int i; - double x = 1.5; - double biom1[12], biom2[12]; + double const x = 1.5; + double biom1[12]; + double biom2[12]; for (i = 0; i < 12; i++) { biom1[i] = i + 1.; @@ -142,7 +141,7 @@ TEST(VegProdTest, VegProdBiomassCO2effect) { TEST(VegProdTest, VegProdSumming) { int vegIndex; - RealD transp_coeff[NVEGTYPES][MAX_LAYERS]; + double transp_coeff[NVEGTYPES][MAX_LAYERS]; for (vegIndex = 0; vegIndex < NVEGTYPES; vegIndex++) { @@ -202,7 +201,7 @@ TEST_F(VegProdFixtureTest, VegProdEstimateVegNotFullVegetation) { SW_CLIMATE_CLIM climateAverages; double inputValues[8]; - double shrubLimit = .2; + double const shrubLimit = .2; // Array holding only grass values double grassOutput[3]; // 3 = Number of grass variables @@ -213,15 +212,15 @@ TEST_F(VegProdFixtureTest, VegProdEstimateVegNotFullVegetation) { // Array holding all values from estimation minus grasses double RelAbundanceL1[5]; // 5 = Number of types minus grasses - double SumGrassesFraction = SW_MISSING; + double const SumGrassesFraction = SW_MISSING; double C4Variables[3]; - Bool fillEmptyWithBareGround = swTRUE; - Bool warnExtrapolation = swTRUE; + Bool const fillEmptyWithBareGround = swTRUE; + Bool const warnExtrapolation = swTRUE; Bool inNorthHem = swTRUE; - Bool fixBareGround = swTRUE; + Bool const fixBareGround = swTRUE; - int nTypes = 8; + int const nTypes = 8; int index; @@ -787,10 +786,10 @@ TEST_F(VegProdFixtureTest, VegProdEstimateVegFullVegetation) { SW_CLIMATE_CLIM climateAverages; int index; - int nTypes = 8; + int const nTypes = 8; double inputValues[8]; - double shrubLimit = .2; + double const shrubLimit = .2; // Array holding only grass values double grassOutput[3]; // 3 = Number of grass variables @@ -808,9 +807,9 @@ TEST_F(VegProdFixtureTest, VegProdEstimateVegFullVegetation) { double grassOutputExpected[3]; Bool fillEmptyWithBareGround = swTRUE; - Bool inNorthHem = swTRUE; - Bool warnExtrapolation = swTRUE; - Bool fixBareGround = swTRUE; + Bool const inNorthHem = swTRUE; + Bool const warnExtrapolation = swTRUE; + Bool const fixBareGround = swTRUE; // Reset "SW_Run.Weather.allHist" @@ -1363,18 +1362,18 @@ TEST_F(VegProdFixtureTest, EstimateVegInputGreaterThanOne1DeathTest) { SW_CLIMATE_CLIM climateAverages; SW_CLIMATE_YEARLY climateOutput; - double SumGrassesFraction = SW_MISSING; + double const SumGrassesFraction = SW_MISSING; double C4Variables[3]; - Bool fillEmptyWithBareGround = swTRUE; - Bool inNorthHem = swTRUE; - Bool warnExtrapolation = swTRUE; - Bool fixBareGround = swTRUE; + Bool const fillEmptyWithBareGround = swTRUE; + Bool const inNorthHem = swTRUE; + Bool const warnExtrapolation = swTRUE; + Bool const fixBareGround = swTRUE; double inputValues[8] = { .0567, .5, .0392, .0981, .3218, .0827, .1293, .0405 }; - double shrubLimit = .2; + double const shrubLimit = .2; // Array holding only grass values double grassOutput[3]; // 3 = Number of grass variables @@ -1467,13 +1466,13 @@ TEST_F(VegProdFixtureTest, EstimateVegInputGreaterThanOne2DeathTest) { double SumGrassesFraction = SW_MISSING; double C4Variables[3]; - Bool fillEmptyWithBareGround = swTRUE; - Bool inNorthHem = swTRUE; - Bool warnExtrapolation = swTRUE; - Bool fixBareGround = swTRUE; + Bool const fillEmptyWithBareGround = swTRUE; + Bool const inNorthHem = swTRUE; + Bool const warnExtrapolation = swTRUE; + Bool const fixBareGround = swTRUE; double inputValues[8]; - double shrubLimit = .2; + double const shrubLimit = .2; // Array holding only grass values double grassOutput[3]; // 3 = Number of grass variables diff --git a/tests/gtests/test_SW_Weather.cc b/tests/gtests/test_SW_Weather.cc index c61c73966..ba579c712 100644 --- a/tests/gtests/test_SW_Weather.cc +++ b/tests/gtests/test_SW_Weather.cc @@ -10,9 +10,9 @@ #include "tests/gtests/sw_testhelpers.h" // for WeatherFixtureTest, tol6 #include "gmock/gmock.h" // for HasSubstr, MakePredicateFor... #include "gtest/gtest.h" // for Test, Message, TestPartResul... -#include // for isnan -#include // for NULL -#include // for strcpy +#include // for isnan, sqrt +#include // for snprintf, NULL + using ::testing::HasSubstr; @@ -73,7 +73,12 @@ TEST_F(WeatherFixtureTest, WeatherSomeMissingValuesDays) { SW_Run.Weather.generateWeatherMethod = 2; // Change directory to get input files with some missing data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_missing/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_missing/weath" + ); SW_MKV_setup( &SW_Run.Markov, @@ -109,11 +114,17 @@ TEST_F(WeatherFixtureTest, WeatherSomeMissingValuesDays) { TEST_F(WeatherFixtureTest, WeatherSomeMissingValuesYears) { - int year, day; + int year; + int day; SW_Run.Weather.generateWeatherMethod = 2; // Change directory to get input files with some missing data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_missing/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_missing/weath" + ); SW_MKV_setup( &SW_Run.Markov, @@ -140,17 +151,18 @@ TEST_F(WeatherFixtureTest, WeatherSomeMissingValuesYears) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error - // Check everyday's value and test if it's `MISSING` + // Check everyday's value and check that it is not `MISSING` for (year = 0; year < 2; year++) { for (day = 0; day < 365; day++) { - EXPECT_TRUE(!missing(SW_Run.Weather.allHist[year]->temp_max[day])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[year]->temp_max[day])); } } } TEST_F(WeatherFixtureTest, WeatherWeatherGeneratorOnly) { - int year, day; + int year; + int day; SW_Run.Weather.generateWeatherMethod = 2; SW_Run.Weather.use_weathergenerator_only = swTRUE; @@ -165,7 +177,12 @@ TEST_F(WeatherFixtureTest, WeatherWeatherGeneratorOnly) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Change directory to get input files with some missing data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_nonexisting/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_nonexisting/weath" + ); SW_WTH_read(&SW_Run.Weather, &SW_Run.Sky, &SW_Run.Model, &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error @@ -179,10 +196,10 @@ TEST_F(WeatherFixtureTest, WeatherWeatherGeneratorOnly) { ); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - // Check everyday's value and test if it's `MISSING` + // Check everyday's value and check that it is not `MISSING` for (year = 0; year < 31; year++) { for (day = 0; day < 365; day++) { - EXPECT_TRUE(!missing(SW_Run.Weather.allHist[year]->temp_max[day])); + EXPECT_FALSE(missing(SW_Run.Weather.allHist[year]->temp_max[day])); } } } @@ -192,7 +209,12 @@ TEST_F(WeatherFixtureTest, ReadAllWeatherTooManyMissingForLOCFDeathTest) { // Error: too many missing values and weather generator turned off // Change to directory without input files - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_nonexisting/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_nonexisting/weath" + ); // Set LOCF (temp) + 0 (PPT) method SW_Run.Weather.generateWeatherMethod = 1; @@ -224,7 +246,7 @@ TEST_F(WeatherFixtureTest, ClimateVariableClimateFromDefaultWeather) { SW_CLIMATE_YEARLY climateOutput; SW_CLIMATE_CLIM climateAverages; - Bool inNorthHem = swTRUE; + Bool const inNorthHem = swTRUE; // Allocate memory // 31 = number of years used in test @@ -337,7 +359,7 @@ TEST_F(WeatherFixtureTest, ClimateVariableClimateFromOneYearWeather) { SW_CLIMATE_YEARLY climateOutput; SW_CLIMATE_CLIM climateAverages; - Bool inNorthHem = swTRUE; + Bool const inNorthHem = swTRUE; // Allocate memory // 1 = number of years used in test @@ -462,7 +484,7 @@ TEST_F(WeatherFixtureTest, ClimateFromDefaultWeatherSouth) { // "South" and not "North" to reduce confusion when calling // `calcSiteClimate()` - Bool inSouthHem = swFALSE; + Bool const inSouthHem = swFALSE; // Allocate memory // 31 = number of years used in test @@ -578,9 +600,9 @@ TEST_F(WeatherFixtureTest, ClimateVariableClimateFromConstantWeather) { SW_CLIMATE_CLIM climateAverages; SW_WEATHER_HIST **allHist = NULL; - unsigned int n_years = 2; + unsigned int const n_years = 2; - Bool inNorthHem = swTRUE; + Bool const inNorthHem = swTRUE; // Allocate memory allocateClimateStructs(n_years, &climateOutput, &climateAverages, &LogInfo); @@ -683,22 +705,23 @@ TEST_F( WeatherFixtureTest, ClimateVariableAverageTemperatureOfDriestQuarterTest ) { - double monthlyPPT[MAX_MONTHS] = { + double const monthlyPPT[MAX_MONTHS] = { .5, .5, .1, .4, .9, 1.0, 1.2, 6.5, 7.5, 1.2, 4., .6 }; - double monthlyTemp[MAX_MONTHS] = { + double const monthlyTemp[MAX_MONTHS] = { -3.2, -.4, 1.2, 3.5, 7.5, 4.5, 6.5, 8.2, 2.0, 3., .1, -.3 }; double result[2]; // 2 = max number of years in test - int month, year; + int month; + int year; double **PPTMon_cm; PPTMon_cm = new double *[MAX_MONTHS]; double **meanTempMon_C = new double *[MAX_MONTHS]; - Bool inNorthHem = swTRUE; + Bool const inNorthHem = swTRUE; for (month = 0; month < MAX_MONTHS; month++) { PPTMon_cm[month] = new double[2]; @@ -767,7 +790,8 @@ TEST_F(WeatherFixtureTest, WeatherMonthlyInputPrioritization) { */ // Initialize any variables - int yearIndex = 0, midJanDay = 14; + int const yearIndex = 0; + int const midJanDay = 14; /* Test if monthly values are not being used */ SW_WTH_setup( @@ -814,8 +838,11 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { * This section uses the test directory "*_gridmet". */ - double result, expectedResult; - int yearIndex = 0, year = 1980, midJanDay = 14; + double result; + double expectedResult; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; /* Test correct priority is being given to input values from DAYMET */ SW_WTH_setup( @@ -827,7 +854,12 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Switch directory to gridmet input folder - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_gridmet/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_gridmet/weath" + ); // Turn off monthly flags SW_Run.Weather.use_cloudCoverMonthly = swFALSE; @@ -850,10 +882,10 @@ TEST_F(WeatherFixtureTest, WeatherInputDailyGridMet) { SW_Run.Weather.desc_rsds = 1; // gridMET rsds is flux density over 24 hours // Reset daily weather values - _clear_hist_weather(SW_Run.Weather.allHist[0]); + clear_hist_weather(SW_Run.Weather.allHist[0]); // Using the new inputs folder, read in year = 1980 - _read_weather_hist( + read_weather_hist( year, SW_Run.Weather.allHist[0], SW_Run.Weather.name_prefix, @@ -921,8 +953,12 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { * This section uses the test directory "*_daymet". */ - double result, expectedResult, tempSlope; - int yearIndex = 0, year = 1980, midJanDay = 14; + double result; + double expectedResult; + double tempSlope; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; /* Test correct priority is being given to input values from DAYMET */ SW_WTH_setup( @@ -934,7 +970,12 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Switch directory to daymet input folder - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_daymet/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_daymet/weath" + ); // Turn off monthly flags SW_Run.Weather.use_cloudCoverMonthly = swFALSE; @@ -954,10 +995,10 @@ TEST_F(WeatherFixtureTest, WeatherInputDayMet) { SW_Run.Weather.desc_rsds = 2; // Reset daily weather values - _clear_hist_weather(SW_Run.Weather.allHist[0]); + clear_hist_weather(SW_Run.Weather.allHist[0]); // Using the new inputs folder, read in year = 1980 - _read_weather_hist( + read_weather_hist( year, SW_Run.Weather.allHist[0], SW_Run.Weather.name_prefix, @@ -1027,8 +1068,11 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { * This section uses the test directory "*_maca". */ - double result, expectedResult; - int yearIndex = 0, year = 1980, midJanDay = 14; + double result; + double expectedResult; + int const yearIndex = 0; + int const year = 1980; + int const midJanDay = 14; /* Test correct priority is being given to input values from MACA */ @@ -1041,7 +1085,12 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Switch directory to daymet input folder - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_maca/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_maca/weath" + ); // Turn off monthly flags SW_Run.Weather.use_cloudCoverMonthly = swFALSE; @@ -1066,10 +1115,10 @@ TEST_F(WeatherFixtureTest, WeatherInputMACA) { SW_Run.Weather.desc_rsds = 1; // MACA rsds is flux density over 24 hours // Reset daily weather values - _clear_hist_weather(SW_Run.Weather.allHist[0]); + clear_hist_weather(SW_Run.Weather.allHist[0]); // Using the new inputs folder, read in year = 1980 - _read_weather_hist( + read_weather_hist( year, SW_Run.Weather.allHist[0], SW_Run.Weather.name_prefix, @@ -1138,9 +1187,12 @@ TEST_F(WeatherFixtureTest, WeatherDailyLOCFInputValues) { We want to make sure when the weather generator method is equal to 1, LOCF is performed on these variables and not ignored */ - int numDaysLOCFTolerance = 366, yearIndex = 0, day; - double cloudCovTestVal = .5, actVapPressTestVal = 4.23, - windSpeedTestVal = 2.12; + int const numDaysLOCFTolerance = 366; + int const yearIndex = 0; + int day; + double const cloudCovTestVal = .5; + double const actVapPressTestVal = 4.23; + double const windSpeedTestVal = 2.12; // Setup and read in weather SW_WTH_setup( @@ -1212,7 +1264,7 @@ TEST_F(WeatherFixtureTest, WeatherDailyInputWrongColumnNumberDeathTest) { */ // Initialize any variables - TimeInt year = 1980; + TimeInt const year = 1980; /* Not the same number of flags as columns */ // Run weather functions and expect an failure (error) @@ -1224,7 +1276,7 @@ TEST_F(WeatherFixtureTest, WeatherDailyInputWrongColumnNumberDeathTest) { // not the columns being read in SW_Run.Weather.n_input_forcings = 0; - _read_weather_hist( + read_weather_hist( year, SW_Run.Weather.allHist[0], SW_Run.Weather.name_prefix, diff --git a/tests/gtests/test_Times.cc b/tests/gtests/test_Times.cc index 4679382e3..ac2afb9d2 100644 --- a/tests/gtests/test_Times.cc +++ b/tests/gtests/test_Times.cc @@ -1,4 +1,4 @@ -#include "include/generic.h" // for Bool, swFALSE, swTRUE, RealD +#include "include/generic.h" // for Bool, swFALSE, swTRUE #include "include/SW_datastructs.h" // for LOG_INFO, SW_WALLTIME #include "include/SW_Defines.h" // for MAX_MONTHS, TimeInt, MAX_DAYS #include "include/SW_Main_lib.h" // for sw_init_logs @@ -9,12 +9,16 @@ namespace { TEST(TimesTest, TimesLeapYear) { - TimeInt days_in_month[MAX_MONTHS], cum_monthdays[MAX_MONTHS]; + TimeInt days_in_month[MAX_MONTHS]; + TimeInt cum_monthdays[MAX_MONTHS]; - unsigned int k, lpadd, - years[] = {1900, 1980, 1981, 2000}; // noleap, leap, noleap, leap years + unsigned int k; + unsigned int lpadd; + // years[]: noleap, leap, noleap, leap years + unsigned int const years[] = {1900, 1980, 1981, 2000}; - Bool kleap, isleap[] = {swFALSE, swTRUE, swFALSE, swTRUE}; + Bool kleap; + Bool const isleap[] = {swFALSE, swTRUE, swFALSE, swTRUE}; Time_init_model(days_in_month); @@ -23,7 +27,7 @@ TEST(TimesTest, TimesLeapYear) { Time_new_year(years[k], days_in_month, cum_monthdays); kleap = isleapyear(years[k]); - lpadd = kleap ? 1 : 0; + lpadd = (kleap != 0u) ? 1 : 0; EXPECT_EQ(kleap, isleap[k]); EXPECT_EQ(Time_days_in_month(Feb, days_in_month), 28 + lpadd); @@ -69,19 +73,23 @@ double valXd(double v1, double v2, int sign, int mday, int delta_days) { TEST(TimesTest, TimesInterpolateMonthlyValues) { // point to the structure that contains cloud coverage monthly values - RealD cloudcov_monthly[MAX_MONTHS]; + double cloudcov_monthly[MAX_MONTHS]; // `interpolate_monthlyValues()` needs an array of length `MAX_DAYS + 1` // if `interpAsBase1` is TRUE - RealD cloudcov_daily[MAX_DAYS + 1]; + double cloudcov_daily[MAX_DAYS + 1]; - TimeInt days_in_month[MAX_MONTHS], cum_monthdays[MAX_MONTHS]; + TimeInt days_in_month[MAX_MONTHS]; + TimeInt cum_monthdays[MAX_MONTHS]; - Bool interpAsBase1 = swFALSE; + Bool const interpAsBase1 = swFALSE; - unsigned int i, k, doy, lpadd, - years[] = {1980, 1981}; // leap year, non-leap year + unsigned int i; + unsigned int k; + unsigned int doy; + unsigned int lpadd; + unsigned int const years[] = {1980, 1981}; // leap year, non-leap year Bool isMon1; @@ -90,7 +98,7 @@ TEST(TimesTest, TimesInterpolateMonthlyValues) { // Loop through years and tests for (k = 0; k < sw_length(years); k++) { Time_new_year(years[k], days_in_month, cum_monthdays); - lpadd = isleapyear(years[k]) ? 1 : 0; + lpadd = (isleapyear(years[k]) != 0u) ? 1 : 0; // Test: all monthlyValues equal to 10 // (not affected by leap/nonleap yrs) @@ -223,14 +231,15 @@ TEST(TimesTest, TimeTracking) { SW_WALLTIME wt; WallTimeSpec start; Bool ok; - int k, n_runs = 10; + int k; + int const n_runs = 10; LOG_INFO LogInfo; // Time difference between start and stop set_walltime(&start, &ok); // ... do some work - if (ok) { + if (ok != 0u) { EXPECT_GE(diff_walltime(start, ok), 0.); } @@ -251,7 +260,7 @@ TEST(TimesTest, TimeTracking) { LogInfo.QuietMode = swTRUE; SW_WT_ReportTime(wt, &LogInfo); - if (wt.has_walltime) { + if (wt.has_walltime != 0u) { EXPECT_EQ(wt.nTimedRuns, n_runs); EXPECT_GE(wt.timeMean, 0.); } else { diff --git a/tests/gtests/test_WaterBalance.cc b/tests/gtests/test_WaterBalance.cc index 1db149c2e..8e4395599 100644 --- a/tests/gtests/test_WaterBalance.cc +++ b/tests/gtests/test_WaterBalance.cc @@ -12,8 +12,8 @@ #include "include/SW_Weather.h" // for SW_WTH_finalize_all_weather #include "tests/gtests/sw_testhelpers.h" // for WaterBalanceFixtureTest #include "gtest/gtest.h" // for Message, EXPECT_EQ, TEST_F +#include // for snprintf #include // for free -#include // for strcpy namespace { /* Test daily water balance and water cycling: @@ -37,7 +37,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceExample1) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -55,7 +55,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSoilTemperature) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -75,7 +75,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithPondedWaterRunonRunoff) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -97,7 +97,12 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithWeatherGeneratorOnly) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error // Point to nonexisting weather data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_nonexisting/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_nonexisting/weath" + ); // Prepare weather data SW_WTH_read(&SW_Run.Weather, &SW_Run.Sky, &SW_Run.Model, &LogInfo); @@ -120,7 +125,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithWeatherGeneratorOnly) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -134,7 +139,12 @@ TEST_F( SW_Run.Weather.generateWeatherMethod = 2; // Point to partial weather data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_missing/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_missing/weath" + ); // Read Markov weather generator input files (they are not normally read) SW_MKV_setup( @@ -167,7 +177,7 @@ TEST_F( for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -192,7 +202,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithHighGravelVolume) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -214,7 +224,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithOneSoilLayer) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -236,7 +246,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMaxSoilLayers) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -258,7 +268,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithVegetationFromClimate1) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -266,11 +276,21 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSWRCvanGenuchten1980) { int i; // Set SWRC and PTF (and SWRC parameter input filename) - strcpy(SW_Run.Site.site_swrc_name, (char *) "vanGenuchten1980"); + (void) snprintf( + SW_Run.Site.site_swrc_name, + sizeof SW_Run.Site.site_swrc_name, + "%s", + "vanGenuchten1980" + ); SW_Run.Site.site_swrc_type = encode_str2swrc(SW_Run.Site.site_swrc_name, &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - strcpy(SW_Run.Site.site_ptf_name, (char *) "Rosetta3"); + (void) snprintf( + SW_Run.Site.site_ptf_name, + sizeof SW_Run.Site.site_ptf_name, + "%s", + "Rosetta3" + ); SW_Run.Site.site_ptf_type = encode_str2ptf(SW_Run.Site.site_ptf_name); SW_Run.Site.site_has_swrcp = swTRUE; @@ -295,7 +315,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSWRCvanGenuchten1980) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -303,11 +323,21 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSWRCFXW) { int i; // Set SWRC and PTF (and SWRC parameter input filename) - strcpy(SW_Run.Site.site_swrc_name, (char *) "FXW"); + (void) snprintf( + SW_Run.Site.site_swrc_name, + sizeof SW_Run.Site.site_swrc_name, + "%s", + "FXW" + ); SW_Run.Site.site_swrc_type = encode_str2swrc(SW_Run.Site.site_swrc_name, &LogInfo); sw_fail_on_error(&LogInfo); // exit test program if unexpected error - strcpy(SW_Run.Site.site_ptf_name, (char *) "neuroFX2021"); + (void) snprintf( + SW_Run.Site.site_ptf_name, + sizeof SW_Run.Site.site_ptf_name, + "%s", + "neuroFX2021" + ); SW_Run.Site.site_ptf_type = encode_str2ptf(SW_Run.Site.site_ptf_name); SW_Run.Site.site_has_swrcp = swTRUE; @@ -332,7 +362,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSWRCFXW) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -340,7 +370,12 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithDaymet) { int i; // Point to Daymet weather data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_daymet/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_daymet/weath" + ); // Adjust simulation years: we have 2 years of Daymet inputs SW_Run.Model.startyr = 1980; @@ -380,7 +415,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithDaymet) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -388,7 +423,12 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithGRIDMET) { int i; // Point to gridMET weather data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_gridmet/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_gridmet/weath" + ); // Adjust simulation years: we have 2 years of gridMET inputs SW_Run.Model.startyr = 1980; @@ -431,7 +471,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithGRIDMET) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -439,7 +479,12 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACA) { int i; // Point to MACA weather data - strcpy(SW_Run.Weather.name_prefix, "Input/data_weather_maca/weath"); + (void) snprintf( + SW_Run.Weather.name_prefix, + sizeof SW_Run.Weather.name_prefix, + "%s", + "Input/data_weather_maca/weath" + ); // Adjust simulation years: we have 2 years of MACA inputs SW_Run.Model.startyr = 1980; @@ -484,7 +529,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithMACA) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } @@ -509,7 +554,7 @@ TEST_F(WaterBalanceFixtureTest, WaterBalanceWithSpinup) { for (i = 0; i < N_WBCHECKS; i++) { EXPECT_EQ(0, SW_Run.SoilWat.wbError[i]) << "Water balance error in test " << i << ": " - << (char *) SW_Run.SoilWat.wbErrorNames[i]; + << SW_Run.SoilWat.wbErrorNames[i]; } } } // namespace diff --git a/tests/gtests/test_generic.cc b/tests/gtests/test_generic.cc index 8fbc3f73b..6723e02cd 100644 --- a/tests/gtests/test_generic.cc +++ b/tests/gtests/test_generic.cc @@ -6,25 +6,25 @@ namespace { const unsigned int N = 9; -unsigned int k; -double x[N] = {-4., -3., -2., -1., 0., 1., 2., 3., 4.}, - // m calculated in R with `for (k in seq_along(x)) print(mean(x[1:k]))` - m[N] = {-4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5, 0}, - // sd calculated in R with `for (k in seq_along(x)) print(sd(x[1:k]))` - sd[N] = { - SW_MISSING, - 0.7071068, - 1., - 1.290994, - 1.581139, - 1.870829, - 2.160247, - 2.44949, - 2.738613 +const double x[N] = {-4., -3., -2., -1., 0., 1., 2., 3., 4.}; +// m calculated in R with `for (k in seq_along(x)) print(mean(x[1:k]))` +const double m[N] = {-4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5, 0}; +// sd calculated in R with `for (k in seq_along(x)) print(sd(x[1:k]))` +const double sd[N] = { + SW_MISSING, + 0.7071068, + 1., + 1.290994, + 1.581139, + 1.870829, + 2.160247, + 2.44949, + 2.738613 }; -float tol = 1e-6; +const double tol = 1e-6; TEST(GenericTest, GenericRunningMean) { + unsigned int k; double m_at_k = 0.; for (k = 0; k < N; k++) { @@ -34,7 +34,9 @@ TEST(GenericTest, GenericRunningMean) { } TEST(GenericTest, GenericRunningSD) { - double ss, sd_at_k; + unsigned int k; + double ss; + double sd_at_k; for (k = 0; k < N; k++) { if (k == 0) { @@ -105,7 +107,8 @@ TEST(GenericTest, GenericStrtok) { */ char *currString; - int startIndex = 0, strLen = 0; + size_t startIndex = 0; + size_t strLen = 0; char emptyDelim[] = ""; char oneDelim[] = "\\"; diff --git a/tests/gtests/test_mymemory.cc b/tests/gtests/test_mymemory.cc index 059d1b152..afc3c1093 100644 --- a/tests/gtests/test_mymemory.cc +++ b/tests/gtests/test_mymemory.cc @@ -14,10 +14,18 @@ TEST(MemoryTest, MemoryRealloc) { // Initialize logs and silence warn/error reporting sw_init_logs(NULL, &LogInfo); - int *ptr0, *ptr1; - int k, n_old = 5, n_new = 7; - size_t size_old = sizeof ptr0 * n_old, size_new = sizeof ptr0 * n_new; - + int *ptr0; + int *ptr1; + int k; + int const n_old = 5; + int const n_new = 7; + size_t const size_old = sizeof ptr0 * n_old; + size_t const size_new = sizeof ptr0 * n_new; + + + // The cast `(int *) Mem_*()` avoids + // "error: assigning to 'int *' from incompatible type 'void *'" + // However, it triggers [cppcoreguidelines-pro-type-cstyle-cast] //--- Expect to reallocate previously allocated memory ------ ptr0 = (int *) Mem_Malloc(size_old, "MemoryRealloc", &LogInfo); diff --git a/tests/gtests/test_rands.cc b/tests/gtests/test_rands.cc index 9f3e8e6f2..14162e1a1 100644 --- a/tests/gtests/test_rands.cc +++ b/tests/gtests/test_rands.cc @@ -11,10 +11,18 @@ using ::testing::HasSubstr; namespace { // This tests the uniform random number generator TEST(RNGTest, RNGUnifZeroToOneOutput) { - sw_random_t rng71, rng71b, rng11, rng12; - int i, n = 10; - double min = 0., max = 1.; - double x71, x71b, x11, x12; + sw_random_t rng71; + sw_random_t rng71b; + sw_random_t rng11; + sw_random_t rng12; + int i; + int const n = 10; + double const min = 0.; + double const max = 1.; + double x71; + double x71b; + double x11; + double x12; // Seed rngs RandSeed(7u, 1u, &rng71); @@ -53,10 +61,19 @@ TEST(RNGTest, RNGUnifZeroToOneOutput) { } TEST(RNGTest, RNGUnifFloatRangeOutput) { - sw_random_t rng71, rng71b, rng11, rng12; - int i, n = 10; - float min = 7.5, max = 77.7; - double x71, x71b, x11, x12, x0; + sw_random_t rng71; + sw_random_t rng71b; + sw_random_t rng11; + sw_random_t rng12; + int i; + int const n = 10; + float const lowVal = 7.5; + float const highVal = 77.7; + double x71; + double x71b; + double x11; + double x12; + double x0; // Seed rngs RandSeed(7u, 1u, &rng71); @@ -66,22 +83,22 @@ TEST(RNGTest, RNGUnifFloatRangeOutput) { for (i = 0; i < n; i++) { - // Produce random numbers and check that within bounds of [min, max) - x71 = RandUniFloatRange(min, max, &rng71); - EXPECT_GE(x71, min); - EXPECT_LT(x71, max); + // Check that random numbers are within bounds of [lowVal, highVal) + x71 = RandUniFloatRange(lowVal, highVal, &rng71); + EXPECT_GE(x71, lowVal); + EXPECT_LT(x71, highVal); - x71b = RandUniFloatRange(min, max, &rng71b); - EXPECT_GE(x71b, min); - EXPECT_LT(x71b, max); + x71b = RandUniFloatRange(lowVal, highVal, &rng71b); + EXPECT_GE(x71b, lowVal); + EXPECT_LT(x71b, highVal); - x11 = RandUniFloatRange(min, max, &rng11); - EXPECT_GE(x11, min); - EXPECT_LT(x11, max); + x11 = RandUniFloatRange(lowVal, highVal, &rng11); + EXPECT_GE(x11, lowVal); + EXPECT_LT(x11, highVal); - x12 = RandUniFloatRange(min, max, &rng12); - EXPECT_GE(x12, min); - EXPECT_LT(x12, max); + x12 = RandUniFloatRange(lowVal, highVal, &rng12); + EXPECT_GE(x12, lowVal); + EXPECT_LT(x12, highVal); // Check that rngs with identical state & sequence produce same output EXPECT_DOUBLE_EQ(x71, x71b); @@ -93,21 +110,30 @@ TEST(RNGTest, RNGUnifFloatRangeOutput) { EXPECT_TRUE(x11 != x12); } - // Check that order of min/max doesn't matter - x0 = RandUniFloatRange(max, min, &rng11); - EXPECT_GE(x0, min); - EXPECT_LT(x0, max); + // Check that order of lowVal/highVal doesn't matter + x0 = RandUniFloatRange(highVal, lowVal, &rng11); + EXPECT_GE(x0, lowVal); + EXPECT_LT(x0, highVal); - // Check that result is min if min == max - EXPECT_FLOAT_EQ(max, RandUniFloatRange(max, max, &rng11)); - EXPECT_FLOAT_EQ(min, RandUniFloatRange(min, min, &rng11)); + // Check that result is lowVal if min == max + EXPECT_FLOAT_EQ(highVal, RandUniFloatRange(highVal, highVal, &rng11)); + EXPECT_FLOAT_EQ(lowVal, RandUniFloatRange(lowVal, lowVal, &rng11)); } TEST(RNGTest, RNGUnifIntRangeOutput) { - sw_random_t rng71, rng71b, rng11, rng12; - int i, n = 10; - int min = 7, max = 123; - double x71, x71b, x11, x12, x0; + sw_random_t rng71; + sw_random_t rng71b; + sw_random_t rng11; + sw_random_t rng12; + int i; + int const n = 10; + int const min = 7; + int const max = 123; + long int x71; + long int x71b; + long int x11; + long int x12; + long int x0; // Seed rngs RandSeed(7u, 1u, &rng71); @@ -157,13 +183,20 @@ TEST(RNGTest, RNGUnifIntRangeOutput) { // This tests the normal random number generator TEST(RNGTest, RNGNormMeanSD) { - sw_random_t rng71, rng71b, rng11, rng12; - int i, n = 10, f = 9999; - double mean = 0., sd = 1., unlikely[2] = {mean - f * sd, mean + f * sd}; - double x71[2] = {-SW_MISSING, SW_MISSING}, - x71b[2] = {-SW_MISSING, SW_MISSING}, - x11[2] = {-SW_MISSING, SW_MISSING}, - x12[2] = {-SW_MISSING, SW_MISSING}; + sw_random_t rng71; + sw_random_t rng71b; + sw_random_t rng11; + sw_random_t rng12; + int i; + int const n = 10; + int const f = 9999; + double const mean = 0.; + double const sd = 1.; + double const unlikely[2] = {mean - f * sd, mean + f * sd}; + double x71[2] = {-SW_MISSING, SW_MISSING}; + double x71b[2] = {-SW_MISSING, SW_MISSING}; + double x11[2] = {-SW_MISSING, SW_MISSING}; + double x12[2] = {-SW_MISSING, SW_MISSING}; // Seed rngs RandSeed(7u, 1u, &rng71); @@ -238,9 +271,20 @@ TEST(RNGTest, RNGBetaZeroToOneOutput) { sw_fail_on_error(&LogInfo); // exit test program if unexpected error - sw_random_t rng71, rng71b, rng11, rng12; - int i, n = 10; - double a = 0.25, b = 2., min = 0., max = 1., x71, x71b, x11, x12; + sw_random_t rng71; + sw_random_t rng71b; + sw_random_t rng11; + sw_random_t rng12; + int i; + int const n = 10; + double const a = 0.25; + double const b = 2.; + double const min = 0.; + double const max = 1.; + double x71; + double x71b; + double x11; + double x12; // Seed rngs RandSeed(7u, 1u, &rng71); diff --git a/tools/run_tidy.sh b/tools/run_tidy.sh new file mode 100755 index 000000000..17b512544 --- /dev/null +++ b/tools/run_tidy.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +#------------------------------------------------------------------------------- +# Verify that clang-tidy is available +if ! command -v clang-tidy > /dev/null 2>&1; then + echo "clang-tidy is not available." + exit 1 +fi + +# Verify that clang-tidy is at least v17 +ctv=$(clang-tidy --version | egrep -o "version [0-9]+.[0-9]+.[0-9]+") +p1=$(echo "$ctv" | egrep -o "[0-9]+.[0-9]+.[0-9]+" | cut -d "." -f 1) + +if [ ! "$p1" -ge 17 ]; then + echo "We require clang-tidy version 17 or later but found" "${ctv}" + exit 1 +fi + + +#------------------------------------------------------------------------------- +process_clangtidy_results() { + local status="$1" + local res="$2" + + if [ $status -eq 0 ]; then + # success: clang-tidy found no check failures + return 0 + else + # failure: clang-tidy produced check output + echo "$res" + exit 1 + fi +} + + +#------------------------------------------------------------------------------- + +echo $'\n'\ +--------------------------------------------------$'\n'\ +"Tidy text-based SOILWAT2"$'\n'\ +-------------------------------------------------- + +res=$(make CPPFLAGS='-DSWDEBUG' tidy-bin 2>/dev/null) +status=$? +process_clangtidy_results $status "$res" + + +echo $'\n'\ +--------------------------------------------------$'\n'\ +"Tidy nc-based SOILWAT2"$'\n'\ +-------------------------------------------------- + +res=$(make CPPFLAGS='-DSWNETCDF -DSWUDUNITS -DSWDEBUG' tidy-bin 2>/dev/null) +status=$? +process_clangtidy_results $status "$res" + + +echo $'\n'\ +--------------------------------------------------$'\n'\ +"Tidy SOILWAT2 library for rSOILWAT2"$'\n'\ +-------------------------------------------------- + +res=$(make CPPFLAGS='-DRSOILWAT' CFLAGS='-Iexternal/Rmock' tidy-bin 2>/dev/null) +status=$? +process_clangtidy_results $status "$res" + + +echo $'\n'\ +--------------------------------------------------$'\n'\ +"Tidy SOILWAT2 library for STEPWAT2"$'\n'\ +-------------------------------------------------- + +res=$(make CPPFLAGS='-DSTEPWAT' tidy-bin 2>/dev/null) +status=$? +process_clangtidy_results $status "$res" + + +echo $'\n'\ +--------------------------------------------------$'\n'\ +"Tidy SOILWAT2 tests with all extra flags"$'\n'\ +-------------------------------------------------- + +res=$(make CPPFLAGS='-DSW2_SpinupEvaluation -DSW2_PET_Test__petfunc_by_temps -DSW2_SolarPosition_Test__hourangles_by_lat_and_doy -DSW2_SolarPosition_Test__hourangles_by_lats' tidy-test 2>/dev/null) +status=$? +process_clangtidy_results $status "$res" + + +#-------------------------------------------------------------------------------