From 248a47b4b011d37d080b7c77c0e09468151285e3 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Fri, 1 Jul 2016 13:01:33 -0700 Subject: [PATCH 01/33] Feature/driver filenames (#547) * refactor filenames and filep structures to only include members specific to each driver, image-like drivers now only use a single PARAMETERS file * fix bug where aggstring was not initialized in parse_output_info.c --- samples/global.param.sample.image.txt | 9 +- .../examples/global_param.image.STEHE.feb.txt | 13 +- .../system/global.image.STEHE.allhistvars.txt | 7 +- .../system/global.image.STEHE.multistream.txt | 6 +- ...global.image.STEHE.restart.FROZEN_SOIL.txt | 8 +- tests/system/global.image.STEHE.restart.txt | 7 +- tests/system/global.image.STEHE.txt | 6 +- tests/test_utils.py | 5 +- tests/unit/shared/test_initialize_files.py | 11 -- .../unit/shared/test_print_library_shared.py | 28 ---- tests/unit/shared/test_vic_log.py | 17 --- vic/drivers/cesm/bld/vic.globalconfig.txt | 11 +- .../cesm/src/display_current_settings.c | 8 +- vic/drivers/cesm/src/get_global_param.c | 35 +---- .../classic/include/vic_driver_classic.h | 38 +++++ vic/drivers/classic/src/alloc_atmos.c | 3 +- vic/drivers/classic/src/alloc_veg_hist.c | 15 +- .../src/initialize_files.c | 3 +- vic/drivers/classic/src/parse_output_info.c | 48 +++--- .../classic/src/print_library_classic.c | 45 ++++++ vic/drivers/classic/src/read_forcing_data.c | 8 +- vic/drivers/classic/src/vic_classic.c | 5 +- vic/drivers/classic/src/write_data.c | 4 +- .../image/src/display_current_settings.c | 11 +- vic/drivers/image/src/get_global_param.c | 88 ++--------- .../python/src/display_current_settings.c | 41 +----- vic/drivers/python/src/globals.c | 2 - vic/drivers/python/vic/vic.py | 2 - .../include/vic_driver_shared_all.h | 45 +----- vic/drivers/shared_all/src/cmd_proc.c | 4 +- vic/drivers/shared_all/src/make_veg_var.c | 12 +- .../shared_all/src/print_library_shared.c | 47 ------ vic/drivers/shared_all/src/vic_history.c | 6 +- vic/drivers/shared_all/src/vic_log.c | 18 +-- .../include/vic_driver_shared_image.h | 34 ++++- vic/drivers/shared_image/src/alloc_atmos.c | 2 - .../shared_image/src/get_nc_dimension.c | 8 +- .../shared_image/src/get_nc_var_attr.c | 14 +- .../shared_image/src/get_nc_varndimensions.c | 9 +- .../shared_image/src/initialize_files.c | 71 +++++++++ .../src/print_library_shared_image.c | 9 +- vic/drivers/shared_image/src/put_nc_attr.c | 3 +- vic/drivers/shared_image/src/vic_alloc.c | 14 +- vic/drivers/shared_image/src/vic_init.c | 138 +++++++++--------- .../shared_image/src/vic_mpi_support.c | 133 +++++++---------- vic/drivers/shared_image/src/vic_start.c | 20 +-- vic/drivers/shared_image/src/vic_write.c | 4 - vic/vic_run/include/vic_log.h | 7 +- 48 files changed, 482 insertions(+), 600 deletions(-) delete mode 100644 tests/unit/shared/test_initialize_files.py rename vic/drivers/{shared_all => classic}/src/initialize_files.c (97%) create mode 100644 vic/drivers/shared_image/src/initialize_files.c diff --git a/samples/global.param.sample.image.txt b/samples/global.param.sample.image.txt index 0c0402e53..8dada2d87 100644 --- a/samples/global.param.sample.image.txt +++ b/samples/global.param.sample.image.txt @@ -139,22 +139,19 @@ WIND_H 10.0 # height of wind speed measurement (m) ####################################################################### # Land Surface Files and Parameters ####################################################################### -SOIL (put the soil parameter path/file here) # Soil parameter path/file +PARAMETERS (put the parameters path/file here) # Parameters path/file BASEFLOW ARNO # ARNO = columns 5-8 are the standard VIC baseflow parameters; NIJSSEN2001 = columns 5-8 of soil file are baseflow parameters from Nijssen et al (2001) JULY_TAVG_SUPPLIED FALSE # TRUE = final column of the soil parameter file will contain average July air temperature, for computing treeline; this will be ignored if COMPUTE_TREELINE is FALSE; FALSE = compute the treeline based on the average July air temperature of the forcings over the simulation period ORGANIC_FRACT FALSE # TRUE = simulate organic soils; soil param file contains 3*Nlayer extra columns, listing for each layer the organic fraction, and the bulk density and soil particle density of the organic matter in the soil layer; FALSE = soil param file does not contain any information about organic soil, and organic fraction should be assumed to be 0 -VEGPARAM (put the veg parameter path/file here) # Veg parameter path/file -ROOT_ZONES 3 # Number of root zones (must match format of veg param file) #LAI_SRC FROM_VEGPARAM # FROM_VEGPARAM = read LAI from veg param file; FROM_VEGHIST = read LAI from veg_hist forcing file #ALB_SRC FROM_VEGPARAM # FROM_VEGPARAM = read ALBEDO from veg param file; FROM_VEGHIST = read ALBEDO from veg_hist forcing file #FCAN_SRC FROM_DEFAULT # FROM_DEFAULT = set all fcanopy values to 1.0; FROM_VEGPARAM = read FCANOPY from veg param file; FROM_VEGHIST = read FCANOPY from veg_hist forcing file -SNOW_BAND 1 # Number of snow bands; if number of snow bands > 1, you must insert the snow band path/file after the number of bands (e.g. SNOW_BAND 5 my_path/my_snow_band_file) +SNOW_BAND TRUE # TRUE if VIC should use snowbands in PARAMETERS file, else FALSE. ####################################################################### # Lake Simulation Parameters -# These need to be un-commented and set to correct values only when running lake model (LAKES is not FALSE) ####################################################################### -#LAKES (put lake parameter path/file here) # Lake parameter path/file +#LAKES TRUE # TRUE if VIC should use the lake module, else FALSE. Requires lake parameters in the PARAMETERS file. #LAKE_PROFILE FALSE # TRUE = User-specified depth-area parameters in lake parameter file; FALSE = VIC computes a parabolic depth-area profile ####################################################################### diff --git a/tests/examples/global_param.image.STEHE.feb.txt b/tests/examples/global_param.image.STEHE.feb.txt index e9c55f04d..6e0ade4ae 100644 --- a/tests/examples/global_param.image.STEHE.feb.txt +++ b/tests/examples/global_param.image.STEHE.feb.txt @@ -15,7 +15,7 @@ FROZEN_SOIL FALSE AERO_RESIST_CANSNOW AR_406 -DOMAIN $test_data_dir/image/Stehekin/parameters/domain.stehekin.20151028.nc +DOMAIN $test_data_dir/image/Stehekin/parameters/domain.stehekin.20151028.nc DOMAIN_TYPE LAT lat DOMAIN_TYPE LON lon DOMAIN_TYPE MASK mask @@ -24,22 +24,19 @@ DOMAIN_TYPE FRAC frac DOMAIN_TYPE YDIM lat DOMAIN_TYPE XDIM lon -FORCING1 $test_data_dir/image/Stehekin/forcings/Stehekin_image_test.forcings_10days. +FORCING1 $test_data_dir/image/Stehekin/forcings/Stehekin_image_test.forcings_10days. FORCE_TYPE AIR_TEMP tas FORCE_TYPE PREC prcp FORCE_TYPE PRESSURE pres FORCE_TYPE SWDOWN dswrf -FORCE_TYPE LWDOWN dlwrf +FORCE_TYPE LWDOWN dlwrf FORCE_TYPE VP shum FORCE_TYPE WIND wind WIND_H 10.0 -SOIL $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc NODES 3 -VEGPARAM $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -ROOT_ZONES 3 -VEGLIB $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -SNOW_BAND 1 $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +SNOW_BAND TRUE RESULT_DIR $result_dir diff --git a/tests/system/global.image.STEHE.allhistvars.txt b/tests/system/global.image.STEHE.allhistvars.txt index e028f616c..328f06909 100644 --- a/tests/system/global.image.STEHE.allhistvars.txt +++ b/tests/system/global.image.STEHE.allhistvars.txt @@ -34,12 +34,9 @@ FORCE_TYPE VP shum FORCE_TYPE WIND wind WIND_H 10.0 -SOIL $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc NODES 3 -VEGPARAM $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -ROOT_ZONES 3 -VEGLIB $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -SNOW_BAND 1 $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +SNOW_BAND TRUE RESULT_DIR $result_dir/ diff --git a/tests/system/global.image.STEHE.multistream.txt b/tests/system/global.image.STEHE.multistream.txt index 416b8faa8..0496f8d96 100644 --- a/tests/system/global.image.STEHE.multistream.txt +++ b/tests/system/global.image.STEHE.multistream.txt @@ -34,12 +34,8 @@ FORCE_TYPE VP shum FORCE_TYPE WIND wind WIND_H 10.0 -SOIL $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc NODES 3 -VEGPARAM $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -ROOT_ZONES 3 -VEGLIB $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -SNOW_BAND 1 $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc RESULT_DIR $result_dir/ diff --git a/tests/system/global.image.STEHE.restart.FROZEN_SOIL.txt b/tests/system/global.image.STEHE.restart.FROZEN_SOIL.txt index 57849869b..97a465d61 100644 --- a/tests/system/global.image.STEHE.restart.FROZEN_SOIL.txt +++ b/tests/system/global.image.STEHE.restart.FROZEN_SOIL.txt @@ -38,20 +38,16 @@ FORCE_TYPE VP shum FORCE_TYPE WIND wind WIND_H 10.0 -SOIL $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.FROZEN_SOIL.nc +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.FROZEN_SOIL.nc BASEFLOW ARNO JULY_TAVG_SUPPLIED FALSE ORGANIC_FRACT FALSE -VEGLIB $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -VEGPARAM $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -ROOT_ZONES 3 LAI_SRC FROM_VEGPARAM -SNOW_BAND 1 $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc RESULT_DIR $result_dir OUTFILE fluxes -AGGFREQ NHOURS 1 +AGGFREQ NHOURS 1 OUTVAR OUT_PREC OUTVAR OUT_RAINF OUTVAR OUT_SNOWF diff --git a/tests/system/global.image.STEHE.restart.txt b/tests/system/global.image.STEHE.restart.txt index 761f5ca98..4b26cb067 100644 --- a/tests/system/global.image.STEHE.restart.txt +++ b/tests/system/global.image.STEHE.restart.txt @@ -38,15 +38,12 @@ FORCE_TYPE VP shum FORCE_TYPE WIND wind WIND_H 10.0 -SOIL $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc BASEFLOW ARNO JULY_TAVG_SUPPLIED FALSE ORGANIC_FRACT FALSE -VEGLIB $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -VEGPARAM $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -ROOT_ZONES 3 LAI_SRC FROM_VEGPARAM -SNOW_BAND 1 $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +SNOW_BAND TRUE RESULT_DIR $result_dir diff --git a/tests/system/global.image.STEHE.txt b/tests/system/global.image.STEHE.txt index 8ef5326cf..ca376639c 100644 --- a/tests/system/global.image.STEHE.txt +++ b/tests/system/global.image.STEHE.txt @@ -34,12 +34,8 @@ FORCE_TYPE VP shum FORCE_TYPE WIND wind WIND_H 10.0 -SOIL $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc NODES 3 -VEGPARAM $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -ROOT_ZONES 3 -VEGLIB $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc -SNOW_BAND 1 $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc RESULT_DIR $result_dir/ diff --git a/tests/test_utils.py b/tests/test_utils.py index 73a45f5a4..641930323 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -59,7 +59,10 @@ def clip_string(string, length=50): def print_tail(string, n=20, indent='\t--->'): '''print tail of multiline string''' - lines = string.decode().splitlines() + try: + lines = string.decode().splitlines() + except UnicodeDecodeError: + lines = string.splitlines() for l in lines[-n:]: print('{0}{1}'.format(indent, l)) diff --git a/tests/unit/shared/test_initialize_files.py b/tests/unit/shared/test_initialize_files.py deleted file mode 100644 index 6ff1d65f6..000000000 --- a/tests/unit/shared/test_initialize_files.py +++ /dev/null @@ -1,11 +0,0 @@ -from vic import lib as vic_lib -from vic import ffi - - -def test_initialize_filenames(): - assert vic_lib.initialize_filenames() is None - assert ffi.string(vic_lib.filenames.init_state) == b'MISSING' - - -def test_initialize_fileps(): - assert vic_lib.initialize_fileps() is None diff --git a/tests/unit/shared/test_print_library_shared.py b/tests/unit/shared/test_print_library_shared.py index 76a1e5365..50147cbae 100644 --- a/tests/unit/shared/test_print_library_shared.py +++ b/tests/unit/shared/test_print_library_shared.py @@ -2,13 +2,6 @@ from vic import lib as vic_lib, ffi -# TODO: fix make_all_vars struct - -# @pytest.fixture() -# def all_data(scope='function'): -# return vic_lib.make_all_vars(4) - - @pytest.fixture() def dmy(scope='function'): d = ffi.new('dmy_struct *') @@ -20,27 +13,10 @@ def dmy(scope='function'): return d -# def test_print_all_data(all_data): -# assert vic_lib.print_cell_data(all_data.cell, vic_lib.options.Nlayer, -# vic_lib.options.Nfrost, 0) is None - - def test_print_dmy(dmy): assert vic_lib.print_dmy(dmy) is None -# def test_print_energy_bal(all_data): -# assert vic_lib.print_energy_bal(all_data.energy, 1, 1) is None - - -def test_print_filenames(): - assert vic_lib.print_filenames(ffi.addressof(vic_lib.filenames)) is None - - -def test_print_filep(): - assert vic_lib.print_filep(ffi.addressof(vic_lib.filep)) is None - - def test_print_global_param(): assert vic_lib.print_global_param( ffi.addressof(vic_lib.global_param)) is None @@ -52,7 +28,3 @@ def test_print_option(): def test_print_parameters(): assert vic_lib.print_parameters(ffi.addressof(vic_lib.param)) is None - - -# def test_print_snow_data(all_data): -# assert vic_lib.print_snow_data(all_data.snow) is None diff --git a/tests/unit/shared/test_vic_log.py b/tests/unit/shared/test_vic_log.py index b3cea45dd..141619b42 100644 --- a/tests/unit/shared/test_vic_log.py +++ b/tests/unit/shared/test_vic_log.py @@ -1,6 +1,4 @@ -import pytest import datetime -import os from vic import lib as vic_lib from vic import ffi @@ -31,18 +29,3 @@ def test_get_logname(): def test_initialize_log(): assert vic_lib.initialize_log() is None - - -def test_setup_logging(): - assert vic_lib.setup_logging(1) is None - - -def test_setup_logging_to_file(tmpdir): - vic_lib.filenames.log_path = (str(tmpdir.mkdir('log')) + '/').encode() - num = 321 - assert vic_lib.setup_logging(num) is None - log_file = os.listdir(ffi.string(vic_lib.filenames.log_path))[0] - print(log_file) - assert log_file.startswith(b'vic.log') - assert log_file.endswith('{0}.txt'.format(num).encode()) - vic_lib.finalize_logging() diff --git a/vic/drivers/cesm/bld/vic.globalconfig.txt b/vic/drivers/cesm/bld/vic.globalconfig.txt index dc11047c0..46bfe6b52 100644 --- a/vic/drivers/cesm/bld/vic.globalconfig.txt +++ b/vic/drivers/cesm/bld/vic.globalconfig.txt @@ -37,14 +37,12 @@ RC_MODE RC_JARVIS # Input Files and PATHS CONSTANTS {vic_constants} LOG_DIR {rundir}/ -SOIL {vic_params} -VEGPARAM {vic_params} +PARAMETERS {vic_params} LAI_SRC FROM_VEGPARAM ALB_SRC FROM_VEGPARAM FCAN_SRC FROM_DEFAULT -VEGLIB {vic_params} -SNOW_BAND 1 -RESULT_DIR {rundir}/vic.testing.h0.nc +SNOW_BAND FALSE +RESULT_DIR {rundir}/ # Domain File DOMAIN {vic_domain} @@ -56,8 +54,9 @@ DOMAIN_TYPE FRAC frac DOMAIN_TYPE YDIM nj DOMAIN_TYPE XDIM ni -N_OUTFILES OUTFILE fluxes +AGGFREQ NDAYS 1 +OUT_FORMAT NETCDF4_CLASSIC OUTVAR OUT_PREC OUTVAR OUT_RAINF OUTVAR OUT_SNOWF diff --git a/vic/drivers/cesm/src/display_current_settings.c b/vic/drivers/cesm/src/display_current_settings.c index 27c1c540b..86351b418 100644 --- a/vic/drivers/cesm/src/display_current_settings.c +++ b/vic/drivers/cesm/src/display_current_settings.c @@ -266,8 +266,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Constants File\t\t%s\n", filenames.constants); - fprintf(LOG_DEST, "Input Soil Data:\n"); - fprintf(LOG_DEST, "Soil file\t\t%s\n", filenames.soil); + fprintf(LOG_DEST, "Parameters file\t\t%s\n", filenames.params); if (options.BASEFLOW == ARNO) { fprintf(LOG_DEST, "BASEFLOW\t\tARNO\n"); } @@ -288,15 +287,12 @@ display_current_settings(int mode) } fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, "Input Veg Data:\n"); - fprintf(LOG_DEST, "Veg library file\t%s\n", filenames.veglib); if (options.VEGLIB_PHOTO) { fprintf(LOG_DEST, "VEGLIB_PHOTO\t\tTRUE\n"); } else { fprintf(LOG_DEST, "VEGLIB_PHOTO\t\tFALSE\n"); } - fprintf(LOG_DEST, "Veg param file\t\t%s\n", filenames.veg); fprintf(LOG_DEST, "ROOT_ZONES\t\t%zu\n", options.ROOT_ZONES); if (options.VEGPARAM_LAI) { fprintf(LOG_DEST, "VEGPARAM_LAI\t\tTRUE\n"); @@ -350,7 +346,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Input Lake Data:\n"); if (options.LAKES) { - fprintf(LOG_DEST, "LAKES\t\tTRUE\t%s\n", filenames.lakeparam); + fprintf(LOG_DEST, "LAKES\t\tTRUE\n"); } else { fprintf(LOG_DEST, "LAKES\t\tFALSE\n"); diff --git a/vic/drivers/cesm/src/get_global_param.c b/vic/drivers/cesm/src/get_global_param.c index b833144ac..0d03d3e10 100644 --- a/vic/drivers/cesm/src/get_global_param.c +++ b/vic/drivers/cesm/src/get_global_param.c @@ -274,8 +274,8 @@ get_global_param(FILE *gp) else if (strcasecmp("DOMAIN_TYPE", optstr) == 0) { get_domain_type(cmdstr); } - else if (strcasecmp("SOIL", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.soil); + else if (strcasecmp("PARAMETERS", optstr) == 0) { + sscanf(cmdstr, "%*s %s", filenames.params); } else if (strcasecmp("ARNO_PARAMS", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); @@ -320,16 +320,10 @@ get_global_param(FILE *gp) sscanf(cmdstr, "%*s %s", flgstr); options.ORGANIC_FRACT = str_to_bool(flgstr); } - else if (strcasecmp("VEGLIB", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.veglib); - } else if (strcasecmp("VEGLIB_PHOTO", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); options.VEGLIB_PHOTO = str_to_bool(flgstr); } - else if (strcasecmp("VEGPARAM", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.veg); - } else if (strcasecmp("LAI_SRC", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); if (strcasecmp("FROM_VEGHIST", flgstr) == 0) { @@ -388,7 +382,6 @@ get_global_param(FILE *gp) } else { options.LAKES = true; - strcpy(filenames.lakeparam, flgstr); } } else if (strcasecmp("LAKE_PROFILE", optstr) == 0) { @@ -458,7 +451,7 @@ validate_filenames(filenames_struct *filenames) extern option_struct options; // Validate log directory - if (strcmp(filenames->result_dir, "MISSING") == 0) { + if (strcmp(filenames->log_path, "MISSING") == 0) { log_err("Log directory must be specified in CESM driver"); } @@ -469,23 +462,11 @@ validate_filenames(filenames_struct *filenames) "begins with \"RESULT_DIR\"."); } - // Validate soil parameter file information - if (strcmp(filenames->soil, "MISSING") == 0) { - log_err("No soil parameter file has been defined. Make sure that the " - "global file defines the soil parameter file on the line that " - "begins with \"SOIL\"."); - } - - // Validate veg parameter information - if (strcmp(filenames->veg, "MISSING") == 0) { - log_err("No vegetation parameter file has been defined. Make sure " - "that the global file defines the vegetation parameter " - "file on the line that begins with \"VEGPARAM\"."); - } - if (strcmp(filenames->veglib, "MISSING") == 0) { - log_err("No vegetation library file has been defined. Make sure " - "that the global file defines the vegetation library file " - "on the line that begins with \"VEGLIB\"."); + // Validate parameter file information + if (strcmp(filenames->params, "MISSING") == 0) { + log_err("A parameters file has not been defined. Make sure that the " + "global file defines the parameters parameter file on the line " + "that begins with \"PARAMETERS\"."); } // Validate snow parameter file diff --git a/vic/drivers/classic/include/vic_driver_classic.h b/vic/drivers/classic/include/vic_driver_classic.h index 5a21d311d..4d66c7865 100644 --- a/vic/drivers/classic/include/vic_driver_classic.h +++ b/vic/drivers/classic/include/vic_driver_classic.h @@ -35,6 +35,42 @@ #define MAX_VEGPARAM_LINE_LENGTH 500 #define ASCII_STATE_FLOAT_FMT "%.16g" +/****************************************************************************** + * @brief file structures + *****************************************************************************/ +typedef struct { + FILE *forcing[MAX_FORCE_FILES]; /**< atmospheric forcing data files */ + FILE *globalparam; /**< global parameters file */ + FILE *constants; /**< model constants parameter file */ + FILE *init_state; /**< initial model state file */ + FILE *lakeparam; /**< lake parameter file */ + FILE *snowband; /**< snow elevation band data file */ + FILE *soilparam; /**< soil parameters for all grid cells */ + FILE *statefile; /**< output model state file */ + FILE *veglib; /**< vegetation parameters for all vege types */ + FILE *vegparam; /**< fractional coverage info for grid cell */ + FILE *logfile; /**< log file */ +} filep_struct; + +/****************************************************************************** + * @brief This structure stores input and output filenames. + *****************************************************************************/ +typedef struct { + char forcing[MAX_FORCE_FILES][MAXSTRING]; /**< atmospheric forcing data file names */ + char f_path_pfx[MAX_FORCE_FILES][MAXSTRING]; /**< path and prefix for atmospheric forcing data file names */ + char global[MAXSTRING]; /**< global control file name */ + char constants[MAXSTRING]; /**< model constants file name */ + char init_state[MAXSTRING]; /**< initial model state file name */ + char lakeparam[MAXSTRING]; /**< lake model constants file */ + char result_dir[MAXSTRING]; /**< directory where results will be written */ + char snowband[MAXSTRING]; /**< snow band parameter file name */ + char soil[MAXSTRING]; /**< soil parameter file name */ + char statefile[MAXSTRING]; /**< name of file in which to store model state */ + char veg[MAXSTRING]; /**< vegetation grid coverage file */ + char veglib[MAXSTRING]; /**< vegetation parameter library file */ + char log_path[MAXSTRING]; /**< Location to write log file to*/ +} filenames_struct; + void alloc_atmos(int, atmos_data_struct **); void alloc_veg_hist(int nrecs, int nveg, veg_hist_struct ***veg_hist); void calc_netlongwave(double *, double, double, double); @@ -50,6 +86,8 @@ void free_veglib(veg_lib_struct **); double get_dist(double lat1, double long1, double lat2, double long2); void get_force_type(char *, int, int *); void get_global_param(FILE *); +void initialize_filenames(void); +void initialize_fileps(void); void initialize_forcing_files(void); void make_in_and_outfiles(filep_struct *filep, filenames_struct *filenames, soil_con_struct *soil, stream_struct **streams, diff --git a/vic/drivers/classic/src/alloc_atmos.c b/vic/drivers/classic/src/alloc_atmos.c index 13a2bbd55..1a61b337b 100644 --- a/vic/drivers/classic/src/alloc_atmos.c +++ b/vic/drivers/classic/src/alloc_atmos.c @@ -63,7 +63,8 @@ alloc_atmos(int nrecs, if (options.LAKES) { (*atmos)[i].channel_in = calloc(NR + 1, sizeof(*(*atmos)[i].channel_in)); - check_alloc_status((*atmos)[i].channel_in, "Memory allocation error."); + check_alloc_status((*atmos)[i].channel_in, + "Memory allocation error."); } if (options.CARBON) { (*atmos)[i].Catm = calloc(NR + 1, sizeof(*(*atmos)[i].Catm)); diff --git a/vic/drivers/classic/src/alloc_veg_hist.c b/vic/drivers/classic/src/alloc_veg_hist.c index d479eea79..840e360ce 100644 --- a/vic/drivers/classic/src/alloc_veg_hist.c +++ b/vic/drivers/classic/src/alloc_veg_hist.c @@ -46,22 +46,27 @@ alloc_veg_hist(int nrecs, for (j = 0; j < nveg + 1; j++) { (*veg_hist)[i][j].albedo = calloc(NR + 1, sizeof(*((*veg_hist)[i][j].albedo))); - check_alloc_status((*veg_hist)[i][j].albedo, "Memory allocation error."); + check_alloc_status((*veg_hist)[i][j].albedo, + "Memory allocation error."); (*veg_hist)[i][j].displacement = calloc(NR + 1, sizeof(*((*veg_hist)[i][j]. displacement))); - check_alloc_status((*veg_hist)[i][j].displacement, "Memory allocation error."); + check_alloc_status((*veg_hist)[i][j].displacement, + "Memory allocation error."); (*veg_hist)[i][j].fcanopy = calloc(NR + 1, sizeof(*((*veg_hist)[i][j]. fcanopy))); - check_alloc_status((*veg_hist)[i][j].fcanopy, "Memory allocation error."); + check_alloc_status((*veg_hist)[i][j].fcanopy, + "Memory allocation error."); (*veg_hist)[i][j].LAI = calloc(NR + 1, sizeof(*((*veg_hist)[i][j].LAI))); - check_alloc_status((*veg_hist)[i][j].LAI, "Memory allocation error."); + check_alloc_status((*veg_hist)[i][j].LAI, + "Memory allocation error."); (*veg_hist)[i][j].roughness = calloc(NR + 1, sizeof(*((*veg_hist)[i][j]. roughness))); - check_alloc_status((*veg_hist)[i][j].roughness, "Memory allocation error."); + check_alloc_status((*veg_hist)[i][j].roughness, + "Memory allocation error."); } } } diff --git a/vic/drivers/shared_all/src/initialize_files.c b/vic/drivers/classic/src/initialize_files.c similarity index 97% rename from vic/drivers/shared_all/src/initialize_files.c rename to vic/drivers/classic/src/initialize_files.c index 1c4699c80..15935fb4f 100644 --- a/vic/drivers/shared_all/src/initialize_files.c +++ b/vic/drivers/classic/src/initialize_files.c @@ -25,7 +25,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *****************************************************************************/ -#include +#include /****************************************************************************** * @brief Initialize all filenames before they are called by the @@ -65,7 +65,6 @@ initialize_fileps() filep.globalparam = NULL; filep.constants = NULL; - filep.domain = NULL; filep.init_state = NULL; filep.lakeparam = NULL; filep.snowband = NULL; diff --git a/vic/drivers/classic/src/parse_output_info.c b/vic/drivers/classic/src/parse_output_info.c index bb9c1b6dc..a784df015 100644 --- a/vic/drivers/classic/src/parse_output_info.c +++ b/vic/drivers/classic/src/parse_output_info.c @@ -35,30 +35,29 @@ parse_output_info(FILE *gp, stream_struct **streams, dmy_struct *dmy_current) { - extern option_struct options; - extern global_param_struct global_param; - - char cmdstr[MAXSTRING]; - char optstr[MAXSTRING]; - char flgstr[MAXSTRING]; - short int streamnum; - char varname[MAXSTRING]; - int outvarnum; - char freq_type_str[MAXSTRING]; - char freq_value_str[MAXSTRING]; - char format[MAXSTRING]; - char typestr[MAXSTRING]; - int type; - char multstr[MAXSTRING]; - char aggstr[MAXSTRING]; - double mult; - unsigned short int freq; - int freq_n; - dmy_struct freq_dmy; - unsigned short int agg_type; - int found; - size_t nstream_vars[MAX_OUTPUT_STREAMS]; - bool default_outputs = false; + extern option_struct options; + + char cmdstr[MAXSTRING]; + char optstr[MAXSTRING]; + char flgstr[MAXSTRING]; + short int streamnum; + char varname[MAXSTRING]; + int outvarnum; + char freq_type_str[MAXSTRING]; + char freq_value_str[MAXSTRING]; + char format[MAXSTRING]; + char typestr[MAXSTRING]; + int type; + char multstr[MAXSTRING]; + char aggstr[MAXSTRING]; + double mult; + unsigned short int freq; + int freq_n; + dmy_struct freq_dmy; + unsigned short int agg_type; + int found; + size_t nstream_vars[MAX_OUTPUT_STREAMS]; + bool default_outputs = false; /** Read through global control file to find output info **/ @@ -195,6 +194,7 @@ parse_output_info(FILE *gp, strcpy(format, ""); strcpy(typestr, ""); strcpy(multstr, ""); + strcpy(aggstr, ""); found = sscanf(cmdstr, "%*s %s %s %s %s %s", varname, format, typestr, multstr, aggstr); if (!found) { diff --git a/vic/drivers/classic/src/print_library_classic.c b/vic/drivers/classic/src/print_library_classic.c index c90b0529c..7aad3bc9c 100644 --- a/vic/drivers/classic/src/print_library_classic.c +++ b/vic/drivers/classic/src/print_library_classic.c @@ -127,3 +127,48 @@ print_atmos_data(atmos_data_struct *atmos, fprintf(LOG_DEST, "\n"); } } + +/****************************************************************************** + * @brief Print filenames structure. + *****************************************************************************/ +void +print_filenames(filenames_struct *fnames) +{ + fprintf(LOG_DEST, "filenames:\n"); + fprintf(LOG_DEST, "\tforcing[0] : %s\n", fnames->forcing[0]); + fprintf(LOG_DEST, "\tforcing[1] : %s\n", fnames->forcing[1]); + fprintf(LOG_DEST, "\tf_path_pfx[0]: %s\n", fnames->f_path_pfx[0]); + fprintf(LOG_DEST, "\tf_path_pfx[1]: %s\n", fnames->f_path_pfx[1]); + fprintf(LOG_DEST, "\tglobal : %s\n", fnames->global); + fprintf(LOG_DEST, "\tconstants : %s\n", fnames->constants); + fprintf(LOG_DEST, "\tinit_state : %s\n", fnames->init_state); + fprintf(LOG_DEST, "\tlakeparam : %s\n", fnames->lakeparam); + fprintf(LOG_DEST, "\tresult_dir : %s\n", fnames->result_dir); + fprintf(LOG_DEST, "\tsnowband : %s\n", fnames->snowband); + fprintf(LOG_DEST, "\tsoil : %s\n", fnames->soil); + fprintf(LOG_DEST, "\tstatefile : %s\n", fnames->statefile); + fprintf(LOG_DEST, "\tveg : %s\n", fnames->veg); + fprintf(LOG_DEST, "\tveglib : %s\n", fnames->veglib); + fprintf(LOG_DEST, "\tlog_path : %s\n", fnames->log_path); +} + +/****************************************************************************** + * @brief Print file path structure. + *****************************************************************************/ +void +print_filep(filep_struct *fp) +{ + fprintf(LOG_DEST, "filep:\n"); + fprintf(LOG_DEST, "\tforcing[0] : %p\n", fp->forcing[0]); + fprintf(LOG_DEST, "\tforcing[1] : %p\n", fp->forcing[1]); + fprintf(LOG_DEST, "\tglobalparam: %p\n", fp->globalparam); + fprintf(LOG_DEST, "\tconstants : %p\n", fp->constants); + fprintf(LOG_DEST, "\tinit_state : %p\n", fp->init_state); + fprintf(LOG_DEST, "\tlakeparam : %p\n", fp->lakeparam); + fprintf(LOG_DEST, "\tsnowband : %p\n", fp->snowband); + fprintf(LOG_DEST, "\tsoilparam : %p\n", fp->soilparam); + fprintf(LOG_DEST, "\tstatefile : %p\n", fp->statefile); + fprintf(LOG_DEST, "\tveglib : %p\n", fp->veglib); + fprintf(LOG_DEST, "\tvegparam : %p\n", fp->vegparam); + fprintf(LOG_DEST, "\tlogfile : %p\n", fp->logfile); +} diff --git a/vic/drivers/classic/src/read_forcing_data.c b/vic/drivers/classic/src/read_forcing_data.c index 4b289db8f..cfaec814c 100644 --- a/vic/drivers/classic/src/read_forcing_data.c +++ b/vic/drivers/classic/src/read_forcing_data.c @@ -53,17 +53,19 @@ read_forcing_data(FILE **infile, if (i != ALBEDO && i != LAI_IN && i != FCANOPY) { forcing_data[i] = calloc(global_param.nrecs * NF, sizeof(*(forcing_data[i]))); - check_alloc_status(forcing_data[i], "Memory allocation error."); + check_alloc_status(forcing_data[i], "Memory allocation error."); } else { (*veg_hist_data)[i] = calloc(param_set.TYPE[i].N_ELEM, sizeof(*((*veg_hist_data)[i]))); - check_alloc_status((*veg_hist_data)[i], "Memory allocation error."); + check_alloc_status((*veg_hist_data)[i], + "Memory allocation error."); for (j = 0; j < param_set.TYPE[i].N_ELEM; j++) { (*veg_hist_data)[i][j] = calloc(global_param.nrecs * NF, sizeof(*((*veg_hist_data)[i] [j]))); - check_alloc_status((*veg_hist_data)[i][j], "Memory allocation error."); + check_alloc_status((*veg_hist_data)[i][j], + "Memory allocation error."); } } } diff --git a/vic/drivers/classic/src/vic_classic.c b/vic/drivers/classic/src/vic_classic.c index 65e46705c..262c3dbf7 100644 --- a/vic/drivers/classic/src/vic_classic.c +++ b/vic/drivers/classic/src/vic_classic.c @@ -99,7 +99,7 @@ main(int argc, fclose(filep.globalparam); // Set Log Destination - setup_logging(MISSING); + setup_logging(MISSING, filenames.log_path, &(filep.logfile)); /** Set model constants **/ if (strcmp(filenames.constants, "MISSING") != 0) { @@ -199,9 +199,6 @@ main(int argc, vic_populate_model_state(&all_vars, filep, soil_con.gridcel, &soil_con, veg_con, lake_con); - /** Update Error Handling Structure **/ - Error.filep = filep; - /** Initialize the storage terms in the water and energy balances **/ initialize_save_data(&all_vars, &atmos[0], &soil_con, veg_con, veg_lib, &lake_con, out_data[0], &save_data); diff --git a/vic/drivers/classic/src/write_data.c b/vic/drivers/classic/src/write_data.c index 738e185bb..1dbdc3bf9 100644 --- a/vic/drivers/classic/src/write_data.c +++ b/vic/drivers/classic/src/write_data.c @@ -105,8 +105,8 @@ write_data(stream_struct *stream, elem_idx < out_metadata[varid].nelem; elem_idx++) { tmp_usiptr[ptr_idx++] = - (unsigned short int) stream->aggdata[var_idx][elem_idx][ - 0]; + (unsigned short int) stream->aggdata[0][var_idx][ + elem_idx][0]; } fwrite(tmp_usiptr, sizeof(unsigned short int), ptr_idx, stream->fh); diff --git a/vic/drivers/image/src/display_current_settings.c b/vic/drivers/image/src/display_current_settings.c index e280ecc11..6df978b2e 100644 --- a/vic/drivers/image/src/display_current_settings.c +++ b/vic/drivers/image/src/display_current_settings.c @@ -269,8 +269,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Constants File\t\t%s\n", filenames.constants); - fprintf(LOG_DEST, "Input Soil Data:\n"); - fprintf(LOG_DEST, "Soil file\t\t%s\n", filenames.soil); + fprintf(LOG_DEST, "Parameters file\t\t%s\n", filenames.params); if (options.BASEFLOW == ARNO) { fprintf(LOG_DEST, "BASEFLOW\t\tARNO\n"); } @@ -291,15 +290,12 @@ display_current_settings(int mode) } fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, "Input Veg Data:\n"); - fprintf(LOG_DEST, "Veg library file\t%s\n", filenames.veglib); if (options.VEGLIB_PHOTO) { fprintf(LOG_DEST, "VEGLIB_PHOTO\t\tTRUE\n"); } else { fprintf(LOG_DEST, "VEGLIB_PHOTO\t\tFALSE\n"); } - fprintf(LOG_DEST, "Veg param file\t\t%s\n", filenames.veg); fprintf(LOG_DEST, "ROOT_ZONES\t\t%zu\n", options.ROOT_ZONES); if (options.VEGPARAM_LAI) { fprintf(LOG_DEST, "VEGPARAM_LAI\t\tTRUE\n"); @@ -353,8 +349,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Input Elevation Data:\n"); if (options.SNOW_BAND > 1) { - fprintf(LOG_DEST, "SNOW_BAND\t\t%zu\t%s\n", options.SNOW_BAND, - filenames.snowband); + fprintf(LOG_DEST, "SNOW_BAND\t\t%zu\n", options.SNOW_BAND); } else if (options.SNOW_BAND == 1) { fprintf(LOG_DEST, @@ -368,7 +363,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Input Lake Data:\n"); if (options.LAKES) { - fprintf(LOG_DEST, "LAKES\t\tTRUE\t%s\n", filenames.lakeparam); + fprintf(LOG_DEST, "LAKES\t\tTRUE\n"); } else { fprintf(LOG_DEST, "LAKES\t\tFALSE\n"); diff --git a/vic/drivers/image/src/get_global_param.c b/vic/drivers/image/src/get_global_param.c index b5a886ada..4d0680b89 100644 --- a/vic/drivers/image/src/get_global_param.c +++ b/vic/drivers/image/src/get_global_param.c @@ -379,16 +379,8 @@ get_global_param(FILE *gp) else if (strcasecmp("DOMAIN_TYPE", optstr) == 0) { get_domain_type(cmdstr); } - else if (strcasecmp("SOIL", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.soil); - } - else if (strcasecmp("ARC_SOIL", optstr) == 0) { - sscanf(cmdstr, "%*s %s", flgstr); - if (strcasecmp("TRUE", flgstr) == 0) { - log_err("\"ARC_SOIL\" is no longer a supported option.\n" - "Please convert your soil parameter file and " - "remove this option from your global file."); - } + else if (strcasecmp("PARAMETERS", optstr) == 0) { + sscanf(cmdstr, "%*s %s", filenames.params); } else if (strcasecmp("ARNO_PARAMS", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); @@ -433,16 +425,10 @@ get_global_param(FILE *gp) sscanf(cmdstr, "%*s %s", flgstr); options.ORGANIC_FRACT = str_to_bool(flgstr); } - else if (strcasecmp("VEGLIB", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.veglib); - } else if (strcasecmp("VEGLIB_PHOTO", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); options.VEGLIB_PHOTO = str_to_bool(flgstr); } - else if (strcasecmp("VEGPARAM", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.veg); - } else if (strcasecmp("LAI_SRC", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); if (strcasecmp("FROM_VEGHIST", flgstr) == 0) { @@ -494,22 +480,15 @@ get_global_param(FILE *gp) "control file."); } } - else if (strcasecmp("ROOT_ZONES", optstr) == 0) { - sscanf(cmdstr, "%*s %zu", &options.ROOT_ZONES); - } else if (strcasecmp("SNOW_BAND", optstr) == 0) { - sscanf(cmdstr, "%*s %zu %s", &options.SNOW_BAND, - filenames.snowband); + sscanf(cmdstr, "%*s %s", flgstr); + if (str_to_bool(flgstr)) { + options.SNOW_BAND = SNOW_BAND_TRUE_BUT_UNSET; + } } else if (strcasecmp("LAKES", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); - if (strcasecmp("FALSE", flgstr) == 0) { - options.LAKES = false; - } - else { - options.LAKES = true; - strcpy(filenames.lakeparam, flgstr); - } + options.LAKES = str_to_bool(flgstr); } else if (strcasecmp("LAKE_PROFILE", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); @@ -846,27 +825,11 @@ get_global_param(FILE *gp) "begins with \"RESULT_DIR\"."); } - // Validate soil parameter file information - if (strcmp(filenames.soil, "MISSING") == 0) { - log_err("No soil parameter file has been defined. Make sure that the " - "global file defines the soil parameter file on the line that " - "begins with \"SOIL\"."); - } - - // Validate veg parameter information - if (strcmp(filenames.veg, "MISSING") == 0) { - log_err("No vegetation parameter file has been defined. Make sure " - "that the global file defines the vegetation parameter " - "file on the line that begins with \"VEGPARAM\"."); - } - if (strcmp(filenames.veglib, "MISSING") == 0) { - log_err("No vegetation library file has been defined. Make sure " - "that the global file defines the vegetation library file " - "on the line that begins with \"VEGLIB\"."); - } - if (options.ROOT_ZONES == 0) { - log_err("ROOT_ZONES must be defined to a positive integer greater " - "than 0, in the global control file."); + // Validate parameter file information + if (strcmp(filenames.params, "MISSING") == 0) { + log_err("A parameters file has not been defined. Make sure that the " + "global file defines the parameters parameter file on the line " + "that begins with \"PARAMETERS\"."); } // Validate SPATIAL_FROST information @@ -900,27 +863,6 @@ get_global_param(FILE *gp) } } - // Validate the elevation band file information - if (options.SNOW_BAND > 1) { - if (strcmp(filenames.snowband, "MISSING") == 0) { - log_err("\"SNOW_BAND\" was specified with %zu elevation bands, " - "but no elevation band file has been defined. " - "Make sure that the global file defines the elevation " - "band file on the line that begins with \"SNOW_BAND\" " - "(after the number of bands).", options.SNOW_BAND); - } - if (options.SNOW_BAND > MAX_BANDS) { - log_err("Global file wants more snow bands (%zu) than are " - "defined by MAX_BANDS (%d). Edit vic_driver_shared.h and " - "recompile.", options.SNOW_BAND, MAX_BANDS); - } - } - else if (options.SNOW_BAND <= 0) { - log_err("Invalid number of elevation bands specified in global " - "file (%zu). Number of bands must be >= 1.", - options.SNOW_BAND); - } - // Validate the input state file information if (options.INIT_STATE) { if (strcmp(filenames.init_state, "MISSING") == 0) { @@ -1040,12 +982,6 @@ get_global_param(FILE *gp) log_err("FULL_ENERGY must be TRUE if the lake model is to " "be run."); } - if (strcmp(filenames.lakeparam, "MISSING") == 0) { - log_err("\"LAKES\" was specified, but no lake parameter " - "file has been defined. Make sure that the global " - "file defines the lake parameter file on the line that " - "begins with \"LAKES\"."); - } if (options.COMPUTE_TREELINE) { log_err("LAKES = TRUE and COMPUTE_TREELINE = TRUE are " "incompatible options."); diff --git a/vic/drivers/python/src/display_current_settings.c b/vic/drivers/python/src/display_current_settings.c index 0514149b3..305ea4892 100644 --- a/vic/drivers/python/src/display_current_settings.c +++ b/vic/drivers/python/src/display_current_settings.c @@ -37,10 +37,6 @@ display_current_settings(int mode) extern option_struct options; extern param_set_struct param_set; extern global_param_struct global_param; - extern filenames_struct filenames; - - int file_num; - print_version(VIC_DRIVER); @@ -242,34 +238,9 @@ display_current_settings(int mode) fprintf(LOG_DEST, "Ncanopy\t\t%zu\n", options.Ncanopy); fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, "Input Forcing Data:\n"); - for (file_num = 0; file_num < 2; file_num++) { - if (global_param.forceyear[file_num] > 0) { - fprintf(LOG_DEST, "Forcing File %d:\t\t%s*\n", file_num + 1, - filenames.f_path_pfx[file_num]); - fprintf(LOG_DEST, "FORCEYEAR\t\t%d\n", - global_param.forceyear[file_num]); - fprintf(LOG_DEST, "FORCEMONTH\t\t%d\n", - global_param.forcemonth[file_num]); - fprintf(LOG_DEST, "FORCEDAY\t\t%d\n", - global_param.forceday[file_num]); - fprintf(LOG_DEST, "FORCESEC\t\t%d\n", - global_param.forcesec[file_num]); - fprintf(LOG_DEST, "N_TYPES\t\t\t%zu\n", - param_set.N_TYPES[file_num]); - fprintf(LOG_DEST, "FORCE_DT\t\t%f\n", param_set.FORCE_DT[file_num]); - } - } fprintf(LOG_DEST, "GRID_DECIMAL\t\t%hu\n", options.GRID_DECIMAL); fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, "Input Domain Data:\n"); - fprintf(LOG_DEST, "Domain file\t\t%s\n", filenames.domain); - - fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, "Constants File\t\t%s\n", filenames.constants); - fprintf(LOG_DEST, "Input Soil Data:\n"); - fprintf(LOG_DEST, "Soil file\t\t%s\n", filenames.soil); if (options.BASEFLOW == ARNO) { fprintf(LOG_DEST, "BASEFLOW\t\tARNO\n"); } @@ -290,15 +261,12 @@ display_current_settings(int mode) } fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, "Input Veg Data:\n"); - fprintf(LOG_DEST, "Veg library file\t%s\n", filenames.veglib); if (options.VEGLIB_PHOTO) { fprintf(LOG_DEST, "VEGLIB_PHOTO\t\tTRUE\n"); } else { fprintf(LOG_DEST, "VEGLIB_PHOTO\t\tFALSE\n"); } - fprintf(LOG_DEST, "Veg param file\t\t%s\n", filenames.veg); fprintf(LOG_DEST, "ROOT_ZONES\t\t%zu\n", options.ROOT_ZONES); if (options.VEGPARAM_LAI) { fprintf(LOG_DEST, "VEGPARAM_LAI\t\tTRUE\n"); @@ -352,8 +320,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Input Elevation Data:\n"); if (options.SNOW_BAND > 1) { - fprintf(LOG_DEST, "SNOW_BAND\t\t%zu\t%s\n", options.SNOW_BAND, - filenames.snowband); + fprintf(LOG_DEST, "SNOW_BAND\t\t%zu\n", options.SNOW_BAND); } else if (options.SNOW_BAND == 1) { fprintf(LOG_DEST, @@ -367,7 +334,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Input Lake Data:\n"); if (options.LAKES) { - fprintf(LOG_DEST, "LAKES\t\tTRUE\t%s\n", filenames.lakeparam); + fprintf(LOG_DEST, "LAKES\t\tTRUE\n"); } else { fprintf(LOG_DEST, "LAKES\t\tFALSE\n"); @@ -382,7 +349,7 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Input State File:\n"); if (options.INIT_STATE) { - fprintf(LOG_DEST, "INIT_STATE\t\tTRUE\t%s\n", filenames.init_state); + fprintf(LOG_DEST, "INIT_STATE\t\tTRUE\n"); if (options.STATE_FORMAT == BINARY) { fprintf(LOG_DEST, "STATE_FORMAT\tBINARY\n"); } @@ -398,7 +365,6 @@ display_current_settings(int mode) fprintf(LOG_DEST, "Output State File:\n"); if (options.SAVE_STATE) { fprintf(LOG_DEST, "SAVE_STATE\t\tTRUE\n"); - fprintf(LOG_DEST, "STATENAME\t\t%s\n", filenames.statefile); fprintf(LOG_DEST, "STATEYEAR\t\t%d\n", global_param.stateyear); fprintf(LOG_DEST, "STATEMONTH\t\t%d\n", global_param.statemonth); fprintf(LOG_DEST, "STATEDAY\t\t%d\n", global_param.stateday); @@ -415,6 +381,5 @@ display_current_settings(int mode) fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Output Data:\n"); - fprintf(LOG_DEST, "Result dir:\t\t%s\n", filenames.result_dir); fprintf(LOG_DEST, "\n"); } diff --git a/vic/drivers/python/src/globals.c b/vic/drivers/python/src/globals.c index 76f5ae5cf..ebd62c189 100644 --- a/vic/drivers/python/src/globals.c +++ b/vic/drivers/python/src/globals.c @@ -37,7 +37,5 @@ size_t NF; /* array index loop counter limit for atmos global_param_struct global_param; option_struct options; parameters_struct param; -filenames_struct filenames; -filep_struct filep; param_set_struct param_set; metadata_struct out_metadata[N_OUTVAR_TYPES]; diff --git a/vic/drivers/python/vic/vic.py b/vic/drivers/python/vic/vic.py index 04f9f6c48..0a610ca05 100644 --- a/vic/drivers/python/vic/vic.py +++ b/vic/drivers/python/vic/vic.py @@ -44,8 +44,6 @@ def _load_lib(lib): lib.initialize_global() lib.initialize_options() lib.initialize_parameters() -lib.initialize_filenames() -lib.initialize_fileps() # TODO: wrappers for individual vic functions. For now, access to lib functions # is made directly through the lib object diff --git a/vic/drivers/shared_all/include/vic_driver_shared_all.h b/vic/drivers/shared_all/include/vic_driver_shared_all.h index efdfb71e2..24d661e89 100644 --- a/vic/drivers/shared_all/include/vic_driver_shared_all.h +++ b/vic/drivers/shared_all/include/vic_driver_shared_all.h @@ -42,6 +42,8 @@ #define OUT_MULT_DEFAULT 0 // Why is this not 1? #define OUT_ASCII_FORMAT_DEFAULT "%.4f" +// Default snow band setting +#define SNOW_BAND_TRUE_BUT_UNSET 99999 /****************************************************************************** * @brief File formats @@ -437,44 +439,6 @@ enum time_units TIME_UNITS_DAYS }; -/****************************************************************************** - * @brief file structures - *****************************************************************************/ -typedef struct { - FILE *forcing[MAX_FORCE_FILES]; /**< atmospheric forcing data files */ - FILE *globalparam; /**< global parameters file */ - FILE *constants; /**< model constants parameter file */ - FILE *domain; /**< domain file */ - FILE *init_state; /**< initial model state file */ - FILE *lakeparam; /**< lake parameter file */ - FILE *snowband; /**< snow elevation band data file */ - FILE *soilparam; /**< soil parameters for all grid cells */ - FILE *statefile; /**< output model state file */ - FILE *veglib; /**< vegetation parameters for all vege types */ - FILE *vegparam; /**< fractional coverage info for grid cell */ - FILE *logfile; /**< log file */ -} filep_struct; - -/****************************************************************************** - * @brief This structure stores input and output filenames. - *****************************************************************************/ -typedef struct { - char forcing[MAX_FORCE_FILES][MAXSTRING]; /**< atmospheric forcing data file names */ - char f_path_pfx[MAX_FORCE_FILES][MAXSTRING]; /**< path and prefix for atmospheric forcing data file names */ - char global[MAXSTRING]; /**< global control file name */ - char domain[MAXSTRING]; /**< domain file name */ - char constants[MAXSTRING]; /**< model constants file name */ - char init_state[MAXSTRING]; /**< initial model state file name */ - char lakeparam[MAXSTRING]; /**< lake model constants file */ - char result_dir[MAXSTRING]; /**< directory where results will be written */ - char snowband[MAXSTRING]; /**< snow band parameter file name */ - char soil[MAXSTRING]; /**< soil parameter file name */ - char statefile[MAXSTRING]; /**< name of file in which to store model state */ - char veg[MAXSTRING]; /**< vegetation grid coverage file */ - char veglib[MAXSTRING]; /**< vegetation parameter library file */ - char log_path[MAXSTRING]; /**< Location to write log file to*/ -} filenames_struct; - /****************************************************************************** * @brief Stores forcing file input information. *****************************************************************************/ @@ -575,7 +539,6 @@ typedef struct { atmos_data_struct *atmos; double dt; energy_bal_struct *energy; - filep_struct filep; size_t rec; double **out_data; stream_struct *output_streams; @@ -641,8 +604,6 @@ void get_parameters(FILE *paramfile); void init_output_list(double **out_data, int write, char *format, int type, double mult); void initialize_energy(energy_bal_struct **energy, size_t nveg); -void initialize_filenames(void); -void initialize_fileps(void); void initialize_global(void); void initialize_options(void); void initialize_parameters(void); @@ -678,8 +639,6 @@ void print_alarm(alarm_struct *alarm); void print_cell_data(cell_data_struct *cell, size_t nlayers, size_t nfrost); void print_dmy(dmy_struct *dmy); void print_energy_bal(energy_bal_struct *eb, size_t nnodes, size_t nfronts); -void print_filenames(filenames_struct *fnames); -void print_filep(filep_struct *fp); void print_force_type(force_type_struct *force_type); void print_global_param(global_param_struct *gp); void print_lake_con(lake_con_struct *lcon, size_t nlnodes); diff --git a/vic/drivers/shared_all/src/cmd_proc.c b/vic/drivers/shared_all/src/cmd_proc.c index 9baa0d6b0..884eea9c5 100644 --- a/vic/drivers/shared_all/src/cmd_proc.c +++ b/vic/drivers/shared_all/src/cmd_proc.c @@ -136,10 +136,10 @@ print_license() fprintf(stdout, "\n Variable Infiltration Capacity (VIC) macroscale hydrologic\n"); fprintf(stdout, - " model version %s, Copyright (C) 2016 Computational Hydrology\n", + " model version %s, Copyright (C) 2016 Computational\n", SHORT_VERSION); fprintf(stdout, - " Group, Dept. of Civil and Environmental Engineering,\n"); + " Hydrology Group, Dept. of Civil and Environmental Engineering,\n"); fprintf(stdout, " University of Washington. VIC comes with ABSOLUTELY NO\n"); fprintf(stdout, diff --git a/vic/drivers/shared_all/src/make_veg_var.c b/vic/drivers/shared_all/src/make_veg_var.c index edd2d7e6e..0c35e4257 100644 --- a/vic/drivers/shared_all/src/make_veg_var.c +++ b/vic/drivers/shared_all/src/make_veg_var.c @@ -49,16 +49,20 @@ make_veg_var(size_t veg_type_num) temp[i][j].NscaleFactor = calloc(options.Ncanopy, sizeof(*(temp[i][j]. NscaleFactor))); - check_alloc_status(temp[i][j].NscaleFactor, "Memory allocation error."); + check_alloc_status(temp[i][j].NscaleFactor, + "Memory allocation error."); temp[i][j].aPARLayer = calloc(options.Ncanopy, sizeof(*(temp[i][j].aPARLayer))); - check_alloc_status(temp[i][j].aPARLayer, "Memory allocation error."); + check_alloc_status(temp[i][j].aPARLayer, + "Memory allocation error."); temp[i][j].CiLayer = calloc(options.Ncanopy, sizeof(*(temp[i][j].CiLayer))); - check_alloc_status(temp[i][j].CiLayer, "Memory allocation error."); + check_alloc_status(temp[i][j].CiLayer, + "Memory allocation error."); temp[i][j].rsLayer = calloc(options.Ncanopy, sizeof(*(temp[i][j].rsLayer))); - check_alloc_status(temp[i][j].rsLayer, "Memory allocation error."); + check_alloc_status(temp[i][j].rsLayer, + "Memory allocation error."); } } } diff --git a/vic/drivers/shared_all/src/print_library_shared.c b/vic/drivers/shared_all/src/print_library_shared.c index 0ce177fcb..b725365f8 100644 --- a/vic/drivers/shared_all/src/print_library_shared.c +++ b/vic/drivers/shared_all/src/print_library_shared.c @@ -231,53 +231,6 @@ print_energy_bal(energy_bal_struct *eb, fprintf(LOG_DEST, "\tsnow_flux : %f\n", eb->snow_flux); } -/****************************************************************************** - * @brief Print filenames structure. - *****************************************************************************/ -void -print_filenames(filenames_struct *fnames) -{ - fprintf(LOG_DEST, "filenames:\n"); - fprintf(LOG_DEST, "\tforcing[0] : %s\n", fnames->forcing[0]); - fprintf(LOG_DEST, "\tforcing[1] : %s\n", fnames->forcing[1]); - fprintf(LOG_DEST, "\tf_path_pfx[0]: %s\n", fnames->f_path_pfx[0]); - fprintf(LOG_DEST, "\tf_path_pfx[1]: %s\n", fnames->f_path_pfx[1]); - fprintf(LOG_DEST, "\tglobal : %s\n", fnames->global); - fprintf(LOG_DEST, "\tconstants : %s\n", fnames->constants); - fprintf(LOG_DEST, "\tdomain : %s\n", fnames->domain); - fprintf(LOG_DEST, "\tinit_state : %s\n", fnames->init_state); - fprintf(LOG_DEST, "\tlakeparam : %s\n", fnames->lakeparam); - fprintf(LOG_DEST, "\tresult_dir : %s\n", fnames->result_dir); - fprintf(LOG_DEST, "\tsnowband : %s\n", fnames->snowband); - fprintf(LOG_DEST, "\tsoil : %s\n", fnames->soil); - fprintf(LOG_DEST, "\tstatefile : %s\n", fnames->statefile); - fprintf(LOG_DEST, "\tveg : %s\n", fnames->veg); - fprintf(LOG_DEST, "\tveglib : %s\n", fnames->veglib); - fprintf(LOG_DEST, "\tlog_path : %s\n", fnames->log_path); -} - -/****************************************************************************** - * @brief Print file path structure. - *****************************************************************************/ -void -print_filep(filep_struct *fp) -{ - fprintf(LOG_DEST, "filep:\n"); - fprintf(LOG_DEST, "\tforcing[0] : %p\n", fp->forcing[0]); - fprintf(LOG_DEST, "\tforcing[1] : %p\n", fp->forcing[1]); - fprintf(LOG_DEST, "\tglobalparam: %p\n", fp->globalparam); - fprintf(LOG_DEST, "\tconstants : %p\n", fp->constants); - fprintf(LOG_DEST, "\tdomain : %p\n", fp->domain); - fprintf(LOG_DEST, "\tinit_state : %p\n", fp->init_state); - fprintf(LOG_DEST, "\tlakeparam : %p\n", fp->lakeparam); - fprintf(LOG_DEST, "\tsnowband : %p\n", fp->snowband); - fprintf(LOG_DEST, "\tsoilparam : %p\n", fp->soilparam); - fprintf(LOG_DEST, "\tstatefile : %p\n", fp->statefile); - fprintf(LOG_DEST, "\tveglib : %p\n", fp->veglib); - fprintf(LOG_DEST, "\tvegparam : %p\n", fp->vegparam); - fprintf(LOG_DEST, "\tlogfile : %p\n", fp->logfile); -} - /****************************************************************************** * @brief Print forcing type structure. *****************************************************************************/ diff --git a/vic/drivers/shared_all/src/vic_history.c b/vic/drivers/shared_all/src/vic_history.c index 51d85c98b..ffd4314a5 100644 --- a/vic/drivers/shared_all/src/vic_history.c +++ b/vic/drivers/shared_all/src/vic_history.c @@ -180,13 +180,15 @@ alloc_aggdata(stream_struct *stream) nelem = out_metadata[stream->varid[j]].nelem; stream->aggdata[i][j] = calloc(nelem, sizeof(*(stream->aggdata[i][j]))); - check_alloc_status(stream->aggdata[i][j], "Memory allocation error."); + check_alloc_status(stream->aggdata[i][j], + "Memory allocation error."); for (k = 0; k < nelem; k++) { // TODO: Also allocate for nbins, for now just setting to size 1 stream->aggdata[i][j][k] = calloc(1, sizeof(*(stream->aggdata[i][j][k]))); - check_alloc_status(stream->aggdata[i][j][k], "Memory allocation error."); + check_alloc_status(stream->aggdata[i][j][k], + "Memory allocation error."); } } } diff --git a/vic/drivers/shared_all/src/vic_log.c b/vic/drivers/shared_all/src/vic_log.c index 1db8f635d..a11cdd2c7 100644 --- a/vic/drivers/shared_all/src/vic_log.c +++ b/vic/drivers/shared_all/src/vic_log.c @@ -112,25 +112,25 @@ initialize_log(void) * @brief Set global log destination *****************************************************************************/ void -setup_logging(int id) +setup_logging(int id, + char log_path[], + FILE **logfile) { - extern filenames_struct filenames; - extern filep_struct filep; - extern FILE *LOG_DEST; - char logfilename[MAXSTRING]; + extern FILE *LOG_DEST; + char logfilename[MAXSTRING]; - if (strcmp(filenames.log_path, "MISSING") != 0) { + if (strcmp(log_path, "MISSING") != 0) { // Create logfile name - get_logname(filenames.log_path, id, logfilename); + get_logname(log_path, id, logfilename); // Open Logfile - filep.logfile = open_file(logfilename, "w"); + *logfile = open_file(logfilename, "w"); // Print log file name to stderr log_info("Initialized Log File: %s", logfilename); // Set Log Destination - LOG_DEST = filep.logfile; + LOG_DEST = *logfile; // Write first line of log file log_info("Initialized Log File: %s", logfilename); diff --git a/vic/drivers/shared_image/include/vic_driver_shared_image.h b/vic/drivers/shared_image/include/vic_driver_shared_image.h index 2b906627f..fcacfba2c 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -154,6 +154,36 @@ typedef struct { double *Cv; /**< array of fractional coverage for nc_types */ } veg_con_map_struct; +/****************************************************************************** + * @brief file structures + *****************************************************************************/ +typedef struct { + FILE *forcing[MAX_FORCE_FILES]; /**< atmospheric forcing data files */ + FILE *globalparam; /**< global parameters file */ + FILE *constants; /**< model constants parameter file */ + FILE *domain; /**< domain file */ + FILE *init_state; /**< initial model state file */ + FILE *paramfile; /**< parameter file */ + FILE *statefile; /**< output model state file */ + FILE *logfile; /**< log file */ +} filep_struct; + +/****************************************************************************** + * @brief This structure stores input and output filenames. + *****************************************************************************/ +typedef struct { + char forcing[MAX_FORCE_FILES][MAXSTRING]; /**< atmospheric forcing data file names */ + char f_path_pfx[MAX_FORCE_FILES][MAXSTRING]; /**< path and prefix for atmospheric forcing data file names */ + char global[MAXSTRING]; /**< global control file name */ + char domain[MAXSTRING]; /**< domain file name */ + char constants[MAXSTRING]; /**< model constants file name */ + char params[MAXSTRING]; /**< model parameters file name */ + char init_state[MAXSTRING]; /**< initial model state file name */ + char result_dir[MAXSTRING]; /**< directory where results will be written */ + char statefile[MAXSTRING]; /**< name of file in which to store model state */ + char log_path[MAXSTRING]; /**< Location to write log file to */ +} filenames_struct; + void add_nveg_to_global_domain(char *nc_name, domain_struct *global_domain); void alloc_atmos(atmos_data_struct *atmos); void alloc_veg_hist(veg_hist_struct *veg_hist); @@ -178,6 +208,8 @@ int get_nc_dtype(unsigned short int dtype); int get_nc_mode(unsigned short int format); void initialize_domain(domain_struct *domain); void initialize_domain_info(domain_info_struct *info); +void initialize_filenames(void); +void initialize_fileps(void); void initialize_global_structures(void); void initialize_history_file(nc_file_struct *nc, stream_struct *stream, dmy_struct *dmy_current); @@ -197,7 +229,7 @@ void print_atmos_data(atmos_data_struct *atmos); void print_domain(domain_struct *domain, bool print_loc); void print_location(location_struct *location); void print_nc_file(nc_file_struct *nc); -void print_nc_var(nc_var_struct *nc_var, size_t ndims); +void print_nc_var(nc_var_struct *nc_var); void print_veg_con_map(veg_con_map_struct *veg_con_map); void put_nc_attr(int nc_id, int var_id, const char *name, const char *value); void set_force_type(char *cmdstr, int file_num, int *field); diff --git a/vic/drivers/shared_image/src/alloc_atmos.c b/vic/drivers/shared_image/src/alloc_atmos.c index dd34131cd..3e060358f 100644 --- a/vic/drivers/shared_image/src/alloc_atmos.c +++ b/vic/drivers/shared_image/src/alloc_atmos.c @@ -67,7 +67,6 @@ alloc_atmos(atmos_data_struct *atmos) if (options.LAKES) { atmos->channel_in = calloc(NR + 1, sizeof(*(atmos->channel_in))); check_alloc_status(atmos->channel_in, "Memory allocation error."); - } if (options.CARBON) { atmos->Catm = calloc(NR + 1, sizeof(*(atmos->Catm))); @@ -81,7 +80,6 @@ alloc_atmos(atmos_data_struct *atmos) atmos->par = calloc(NR + 1, sizeof(*(atmos->par))); check_alloc_status(atmos->par, "Memory allocation error."); - } } diff --git a/vic/drivers/shared_image/src/get_nc_dimension.c b/vic/drivers/shared_image/src/get_nc_dimension.c index 73690e434..cdbbb3943 100644 --- a/vic/drivers/shared_image/src/get_nc_dimension.c +++ b/vic/drivers/shared_image/src/get_nc_dimension.c @@ -44,12 +44,14 @@ get_nc_dimension(char *nc_name, // get dimension id status = nc_inq_dimid(nc_id, dim_name, &dim_id); - check_nc_status(status, "Error getting dimension id %s in %s", dim_name, nc_name); + check_nc_status(status, "Error getting dimension id %s in %s", dim_name, + nc_name); // get dimension size status = nc_inq_dimlen(nc_id, dim_id, &dim_size); - check_nc_status(status, "Error getting dimension size for dim %s in %s", dim_name, - nc_name); + check_nc_status(status, "Error getting dimension size for dim %s in %s", + dim_name, + nc_name); // close the netcdf file status = nc_close(nc_id); diff --git a/vic/drivers/shared_image/src/get_nc_var_attr.c b/vic/drivers/shared_image/src/get_nc_var_attr.c index 6906d3467..418f56277 100644 --- a/vic/drivers/shared_image/src/get_nc_var_attr.c +++ b/vic/drivers/shared_image/src/get_nc_var_attr.c @@ -46,12 +46,14 @@ get_nc_var_attr(char *nc_name, // get variable id status = nc_inq_varid(nc_id, var_name, &var_id); - check_nc_status(status, "Error getting variable id %s in %s", var_name, nc_name); + check_nc_status(status, "Error getting variable id %s in %s", var_name, + nc_name); // get size of the attribute status = nc_inq_attlen(nc_id, var_id, attr_name, &attr_len); - check_nc_status(status, "Error getting attribute length for %s:%s in %s", var_name, - attr_name, nc_name); + check_nc_status(status, "Error getting attribute length for %s:%s in %s", + var_name, + attr_name, nc_name); // allocate memory for attribute *attr = malloc((attr_len + 1) * sizeof(**attr)); @@ -59,8 +61,10 @@ get_nc_var_attr(char *nc_name, // read attribute text status = nc_get_att_text(nc_id, var_id, attr_name, *attr); - check_nc_status(status, "Error getting netCDF attribute %s for var %s in %s", attr_name, - var_name, nc_name); + check_nc_status(status, + "Error getting netCDF attribute %s for var %s in %s", + attr_name, + var_name, nc_name); // we need to null terminate the string ourselves according to NetCDF docs (*attr)[attr_len] = '\0'; diff --git a/vic/drivers/shared_image/src/get_nc_varndimensions.c b/vic/drivers/shared_image/src/get_nc_varndimensions.c index f6021dfec..1f4131eae 100644 --- a/vic/drivers/shared_image/src/get_nc_varndimensions.c +++ b/vic/drivers/shared_image/src/get_nc_varndimensions.c @@ -44,12 +44,15 @@ get_nc_varndimensions(char *nc_name, // get variable id status = nc_inq_varid(nc_id, var_name, &var_id); - check_nc_status(status, "Error getting variable id %s in %s", var_name, nc_name); + check_nc_status(status, "Error getting variable id %s in %s", var_name, + nc_name); // get number of dimensions status = nc_inq_varndims(nc_id, var_id, &ndims); - check_nc_status(status, "Error getting number of dimensions for var %s in %s", var_name, - nc_name); + check_nc_status(status, + "Error getting number of dimensions for var %s in %s", + var_name, + nc_name); // close the netcdf file status = nc_close(nc_id); diff --git a/vic/drivers/shared_image/src/initialize_files.c b/vic/drivers/shared_image/src/initialize_files.c new file mode 100644 index 000000000..22b97f651 --- /dev/null +++ b/vic/drivers/shared_image/src/initialize_files.c @@ -0,0 +1,71 @@ +/****************************************************************************** + * @section DESCRIPTION + * + * This subroutine initalizes all filefilenames before they are called by + * the model. + * + * @section LICENSE + * + * The Variable Infiltration Capacity (VIC) macroscale hydrological model + * Copyright (C) 2016 The Computational Hydrology Group, Department of Civil + * and Environmental Engineering, University of Washington. + * + * The VIC model is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *****************************************************************************/ + +#include + +/****************************************************************************** + * @brief Initialize all filenames before they are called by the + * model. + *****************************************************************************/ +void +initialize_filenames() +{ + extern filenames_struct filenames; + + size_t i; + + strcpy(filenames.init_state, "MISSING"); + strcpy(filenames.statefile, "MISSING"); + strcpy(filenames.constants, "MISSING"); + strcpy(filenames.params, "MISSING"); + strcpy(filenames.result_dir, "MISSING"); + strcpy(filenames.log_path, "MISSING"); + for (i = 0; i < 2; i++) { + strcpy(filenames.f_path_pfx[i], "MISSING"); + } +} + +/****************************************************************************** + * @brief Initialize all file pointers + *****************************************************************************/ +void +initialize_fileps() +{ + extern filep_struct filep; + + size_t i; + + filep.globalparam = NULL; + filep.constants = NULL; + filep.init_state = NULL; + filep.paramfile = NULL; + filep.statefile = NULL; + filep.logfile = NULL; + for (i = 0; i < 2; i++) { + filep.forcing[i] = NULL; + } +} diff --git a/vic/drivers/shared_image/src/print_library_shared_image.c b/vic/drivers/shared_image/src/print_library_shared_image.c index 79bd445b9..359bb1984 100644 --- a/vic/drivers/shared_image/src/print_library_shared_image.c +++ b/vic/drivers/shared_image/src/print_library_shared_image.c @@ -157,21 +157,20 @@ print_nc_file(nc_file_struct *nc) * @brief Print netCDF variable structure. *****************************************************************************/ void -print_nc_var(nc_var_struct *nc_var, - size_t ndims) +print_nc_var(nc_var_struct *nc_var) { size_t i; fprintf(LOG_DEST, "nc_var:\n"); fprintf(LOG_DEST, "\tnc_varid: %d\n", nc_var->nc_varid); fprintf(LOG_DEST, "\tnc_type: %d\n", nc_var->nc_type); - fprintf(LOG_DEST, "\tnc_dimids:"); - for (i = 0; i < ndims; i++) { + fprintf(LOG_DEST, "\tnc_dimids (%zu):", nc_var->nc_dims); + for (i = 0; i < nc_var->nc_dims; i++) { fprintf(LOG_DEST, "\t%d", nc_var->nc_dimids[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tnc_counts:"); - for (i = 0; i < ndims; i++) { + for (i = 0; i < nc_var->nc_dims; i++) { fprintf(LOG_DEST, "\t%zu", nc_var->nc_counts[i]); } fprintf(LOG_DEST, "\n"); diff --git a/vic/drivers/shared_image/src/put_nc_attr.c b/vic/drivers/shared_image/src/put_nc_attr.c index ce1c3504d..90c05e842 100644 --- a/vic/drivers/shared_image/src/put_nc_attr.c +++ b/vic/drivers/shared_image/src/put_nc_attr.c @@ -38,5 +38,6 @@ put_nc_attr(int nc_id, int status; status = nc_put_att_text(nc_id, var_id, name, strlen(value), value); - check_nc_status(status, "Error adding %s attribute in ncid %d", name, nc_id); + check_nc_status(status, "Error adding %s attribute in ncid %d", name, + nc_id); } diff --git a/vic/drivers/shared_image/src/vic_alloc.c b/vic/drivers/shared_image/src/vic_alloc.c index c63a62da9..da4220261 100644 --- a/vic/drivers/shared_image/src/vic_alloc.c +++ b/vic/drivers/shared_image/src/vic_alloc.c @@ -75,7 +75,6 @@ vic_alloc(void) // allocate memory for lake structure lake_con = malloc(local_domain.ncells_active * sizeof(*lake_con)); check_alloc_status(lake_con, "Memory allocation error."); - } // all_vars allocation @@ -110,7 +109,8 @@ vic_alloc(void) check_alloc_status(soil_con[i].Pfactor, "Memory allocation error."); soil_con[i].AboveTreeLine = calloc(options.SNOW_BAND, sizeof(*(soil_con[i].AboveTreeLine))); - check_alloc_status(soil_con[i].AboveTreeLine, "Memory allocation error."); + check_alloc_status(soil_con[i].AboveTreeLine, + "Memory allocation error."); initialize_soil_con(&(soil_con[i])); @@ -136,16 +136,18 @@ vic_alloc(void) for (j = 0; j < veg_con_map[i].nv_active; j++) { veg_con[i][j].zone_depth = calloc(options.ROOT_ZONES, sizeof(*(veg_con[i][j].zone_depth))); - check_alloc_status(veg_con[i][j].zone_depth, "Memory allocation error."); + check_alloc_status(veg_con[i][j].zone_depth, + "Memory allocation error."); veg_con[i][j].zone_fract = calloc(options.ROOT_ZONES, sizeof(*(veg_con[i][j].zone_fract))); - check_alloc_status(veg_con[i][j].zone_fract, "Memory allocation error."); + check_alloc_status(veg_con[i][j].zone_fract, + "Memory allocation error."); if (options.CARBON) { veg_con[i][j].CanopLayerBnd = calloc(options.Ncanopy, sizeof(*(veg_con[i][j]. CanopLayerBnd))); - check_alloc_status(veg_con[i][j].CanopLayerBnd, "Memory allocation error."); - + check_alloc_status(veg_con[i][j].CanopLayerBnd, + "Memory allocation error."); } initialize_veg_con(&(veg_con[i][j])); } diff --git a/vic/drivers/shared_image/src/vic_init.c b/vic/drivers/shared_image/src/vic_init.c index c1a9b1b14..353453cc8 100644 --- a/vic/drivers/shared_image/src/vic_init.c +++ b/vic/drivers/shared_image/src/vic_init.c @@ -125,7 +125,7 @@ vic_init(void) // overstory for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_int(filenames.veglib, "overstory", + get_scatter_nc_field_int(filenames.params, "overstory", d3start, d3count, ivar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].overstory = ivar[i]; @@ -135,7 +135,7 @@ vic_init(void) // rarc for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "rarc", + get_scatter_nc_field_double(filenames.params, "rarc", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].rarc = (double) dvar[i]; @@ -145,7 +145,7 @@ vic_init(void) // rmin for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "rmin", + get_scatter_nc_field_double(filenames.params, "rmin", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].rmin = (double) dvar[i]; @@ -155,7 +155,7 @@ vic_init(void) // wind height for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "wind_h", + get_scatter_nc_field_double(filenames.params, "wind_h", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].wind_h = (double) dvar[i]; @@ -165,7 +165,7 @@ vic_init(void) // RGL for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "RGL", + get_scatter_nc_field_double(filenames.params, "RGL", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].RGL = (double)dvar[i]; @@ -175,7 +175,7 @@ vic_init(void) // rad_atten for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "rad_atten", + get_scatter_nc_field_double(filenames.params, "rad_atten", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].rad_atten = (double) dvar[i]; @@ -185,7 +185,7 @@ vic_init(void) // wind_atten for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "wind_atten", + get_scatter_nc_field_double(filenames.params, "wind_atten", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].wind_atten = (double) dvar[i]; @@ -195,7 +195,7 @@ vic_init(void) // trunk_ratio for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "trunk_ratio", + get_scatter_nc_field_double(filenames.params, "trunk_ratio", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].trunk_ratio = (double) dvar[i]; @@ -208,7 +208,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < MONTHS_PER_YEAR; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veglib, "LAI", + get_scatter_nc_field_double(filenames.params, "LAI", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].LAI[k] = (double) dvar[i]; @@ -225,7 +225,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < MONTHS_PER_YEAR; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veglib, "albedo", + get_scatter_nc_field_double(filenames.params, "albedo", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].albedo[k] = (double) dvar[i]; @@ -239,7 +239,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < MONTHS_PER_YEAR; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veglib, "veg_rough", + get_scatter_nc_field_double(filenames.params, "veg_rough", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].roughness[k] = (double) dvar[i]; @@ -252,7 +252,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < MONTHS_PER_YEAR; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veglib, "displacement", + get_scatter_nc_field_double(filenames.params, "displacement", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].displacement[k] = (double) dvar[i]; @@ -280,7 +280,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < MONTHS_PER_YEAR; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veglib, "fcanopy", + get_scatter_nc_field_double(filenames.params, "fcanopy", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].fcanopy[k] = (double) dvar[i]; @@ -294,7 +294,7 @@ vic_init(void) // Ctype for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_int(filenames.veglib, "Ctype", + get_scatter_nc_field_int(filenames.params, "Ctype", d3start, d3count, ivar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].Ctype = ivar[i]; @@ -310,7 +310,7 @@ vic_init(void) // MaxCarboxRate for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "MaxCarboxRate", + get_scatter_nc_field_double(filenames.params, "MaxCarboxRate", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].MaxCarboxRate = (double) dvar[i]; @@ -324,7 +324,7 @@ vic_init(void) // MaxETransport or CO2Specificity for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "MaxiE_or_CO2Spec", + get_scatter_nc_field_double(filenames.params, "MaxiE_or_CO2Spec", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { if (dvar[i] < 0) { @@ -344,7 +344,7 @@ vic_init(void) // LightUseEff for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "LUE", + get_scatter_nc_field_double(filenames.params, "LUE", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].LightUseEff = (double) dvar[i]; @@ -359,7 +359,7 @@ vic_init(void) // Nscale flag for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_int(filenames.veglib, "Nscale", + get_scatter_nc_field_int(filenames.params, "Nscale", d3start, d3count, ivar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].NscaleFlag = ivar[i]; @@ -374,7 +374,7 @@ vic_init(void) // Wnpp_inhib for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "Wnpp_inhib", + get_scatter_nc_field_double(filenames.params, "Wnpp_inhib", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].Wnpp_inhib = (double) dvar[i]; @@ -389,7 +389,7 @@ vic_init(void) // NPPfactor_sat for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veglib, "NPPfactor_sat", + get_scatter_nc_field_double(filenames.params, "NPPfactor_sat", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_lib[i][j].NPPfactor_sat = (double) dvar[i]; @@ -406,7 +406,7 @@ vic_init(void) // read_soilparam() // Nlayer - options.Nlayer = get_nc_dimension(filenames.soil, "nlayer"); + options.Nlayer = get_nc_dimension(filenames.params, "nlayer"); // Validate Nlayer if ((options.FULL_ENERGY || @@ -434,35 +434,35 @@ vic_init(void) } // b_infilt - get_scatter_nc_field_double(filenames.soil, "infilt", + get_scatter_nc_field_double(filenames.params, "infilt", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].b_infilt = (double) dvar[i]; } // Ds - get_scatter_nc_field_double(filenames.soil, "Ds", + get_scatter_nc_field_double(filenames.params, "Ds", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Ds = (double) dvar[i]; } // Dsmax - get_scatter_nc_field_double(filenames.soil, "Dsmax", + get_scatter_nc_field_double(filenames.params, "Dsmax", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Dsmax = (double) dvar[i]; } // Ws - get_scatter_nc_field_double(filenames.soil, "Ws", + get_scatter_nc_field_double(filenames.params, "Ws", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Ws = (double) dvar[i]; } // c - get_scatter_nc_field_double(filenames.soil, "c", + get_scatter_nc_field_double(filenames.params, "c", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].c = (double) dvar[i]; @@ -471,7 +471,7 @@ vic_init(void) // expt: unsaturated hydraulic conductivity exponent for each layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "expt", + get_scatter_nc_field_double(filenames.params, "expt", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].expt[j] = (double) dvar[i]; @@ -481,7 +481,7 @@ vic_init(void) // Ksat: saturated hydraulic conductivity for each layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "Ksat", + get_scatter_nc_field_double(filenames.params, "Ksat", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Ksat[j] = (double) dvar[i]; @@ -491,7 +491,7 @@ vic_init(void) // init_moist: initial soil moisture for cold start for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "init_moist", + get_scatter_nc_field_double(filenames.params, "init_moist", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].init_moist[j] = (double) dvar[i]; @@ -501,7 +501,7 @@ vic_init(void) // phi_s for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "phi_s", + get_scatter_nc_field_double(filenames.params, "phi_s", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].phi_s[j] = (double) dvar[i]; @@ -509,7 +509,7 @@ vic_init(void) } // elevation: mean grid cell elevation - get_scatter_nc_field_double(filenames.soil, "elev", + get_scatter_nc_field_double(filenames.params, "elev", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].elevation = (double) dvar[i]; @@ -518,7 +518,7 @@ vic_init(void) // depth: thickness for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "depth", + get_scatter_nc_field_double(filenames.params, "depth", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].depth[j] = (double) dvar[i]; @@ -526,14 +526,14 @@ vic_init(void) } // avg_temp: mean grid temperature - get_scatter_nc_field_double(filenames.soil, "avg_T", + get_scatter_nc_field_double(filenames.params, "avg_T", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].avg_temp = (double) dvar[i]; } // dp: damping depth - get_scatter_nc_field_double(filenames.soil, "dp", + get_scatter_nc_field_double(filenames.params, "dp", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].dp = (double) dvar[i]; @@ -542,7 +542,7 @@ vic_init(void) // bubble: bubbling pressure for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "bubble", + get_scatter_nc_field_double(filenames.params, "bubble", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].bubble[j] = (double) dvar[i]; @@ -552,7 +552,7 @@ vic_init(void) // quartz: quartz content for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "quartz", + get_scatter_nc_field_double(filenames.params, "quartz", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].quartz[j] = (double) dvar[i]; @@ -562,7 +562,7 @@ vic_init(void) // bulk_dens_min: mineral bulk density for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "bulk_density", + get_scatter_nc_field_double(filenames.params, "bulk_density", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].bulk_dens_min[j] = (double) dvar[i]; @@ -572,7 +572,7 @@ vic_init(void) // soil_dens_min: mineral soil density for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "soil_density", + get_scatter_nc_field_double(filenames.params, "soil_density", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].soil_dens_min[j] = (double) dvar[i]; @@ -585,7 +585,7 @@ vic_init(void) // organic for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "organic", + get_scatter_nc_field_double(filenames.params, "organic", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].organic[j] = (double) dvar[i]; @@ -595,7 +595,7 @@ vic_init(void) // bulk_dens_org: organic bulk density for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "bulk_density_org", + get_scatter_nc_field_double(filenames.params, "bulk_density_org", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].bulk_dens_org[j] = (double) dvar[i]; @@ -605,7 +605,7 @@ vic_init(void) // soil_dens_org: organic soil density for each soil layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "soil_density_org", + get_scatter_nc_field_double(filenames.params, "soil_density_org", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].soil_dens_org[j] = (double) dvar[i]; @@ -617,7 +617,7 @@ vic_init(void) // Note this value is multiplied with the maximum moisture in each layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "Wcr_FRACT", + get_scatter_nc_field_double(filenames.params, "Wcr_FRACT", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Wcr[j] = (double) dvar[i]; @@ -628,7 +628,7 @@ vic_init(void) // Note this value is multiplied with the maximum moisture in each layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "Wpwp_FRACT", + get_scatter_nc_field_double(filenames.params, "Wpwp_FRACT", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Wpwp[j] = (double) dvar[i]; @@ -636,21 +636,21 @@ vic_init(void) } // rough: soil roughness - get_scatter_nc_field_double(filenames.soil, "rough", + get_scatter_nc_field_double(filenames.params, "rough", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].rough = (double) dvar[i]; } // snow_rough: snow roughness - get_scatter_nc_field_double(filenames.soil, "snow_rough", + get_scatter_nc_field_double(filenames.params, "snow_rough", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].snow_rough = (double) dvar[i]; } // annual_prec: annual precipitation - get_scatter_nc_field_double(filenames.soil, "annual_prec", + get_scatter_nc_field_double(filenames.params, "annual_prec", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].annual_prec = (double) dvar[i]; @@ -659,7 +659,7 @@ vic_init(void) // resid_moist: residual moisture content for each layer for (j = 0; j < options.Nlayer; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.soil, "resid_moist", + get_scatter_nc_field_double(filenames.params, "resid_moist", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].resid_moist[j] = (double) dvar[i]; @@ -667,7 +667,7 @@ vic_init(void) } // fs_active: frozen soil active flag - get_scatter_nc_field_int(filenames.soil, "fs_active", + get_scatter_nc_field_int(filenames.params, "fs_active", d2start, d2count, ivar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].FS_ACTIVE = (char) ivar[i]; @@ -676,7 +676,7 @@ vic_init(void) // spatial snow if (options.SPATIAL_SNOW) { // max_snow_distrib_slope - get_scatter_nc_field_double(filenames.soil, "max_snow_distrib_slope", + get_scatter_nc_field_double(filenames.params, "max_snow_distrib_slope", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].max_snow_distrib_slope = (double) dvar[i]; @@ -686,7 +686,7 @@ vic_init(void) // spatial frost if (options.SPATIAL_FROST) { // frost_slope: slope of frozen soil distribution - get_scatter_nc_field_double(filenames.soil, "frost_slope", + get_scatter_nc_field_double(filenames.params, "frost_slope", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].frost_slope = (double) dvar[i]; @@ -953,7 +953,7 @@ vic_init(void) // AreaFract: fraction of grid cell in each snow band for (j = 0; j < options.SNOW_BAND; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.snowband, "AreaFract", + get_scatter_nc_field_double(filenames.params, "AreaFract", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].AreaFract[j] = (double) dvar[i]; @@ -962,7 +962,7 @@ vic_init(void) // elevation: elevation of each snow band for (j = 0; j < options.SNOW_BAND; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.snowband, "elevation", + get_scatter_nc_field_double(filenames.params, "elevation", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].BandElev[j] = (double) dvar[i]; @@ -971,7 +971,7 @@ vic_init(void) // Pfactor: precipitation multiplier for each snow band for (j = 0; j < options.SNOW_BAND; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.snowband, "Pfactor", + get_scatter_nc_field_double(filenames.params, "Pfactor", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { soil_con[i].Pfactor[j] = (double) dvar[i]; @@ -1090,7 +1090,7 @@ vic_init(void) for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veg, "Cv", + get_scatter_nc_field_double(filenames.params, "Cv", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { veg_con_map[i].Cv[j] = (double) dvar[i]; @@ -1140,7 +1140,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < options.ROOT_ZONES; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veg, "root_depth", + get_scatter_nc_field_double(filenames.params, "root_depth", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { vidx = veg_con_map[i].vidx[j]; @@ -1156,7 +1156,7 @@ vic_init(void) d4start[0] = j; for (k = 0; k < options.ROOT_ZONES; k++) { d4start[1] = k; - get_scatter_nc_field_double(filenames.veg, "root_fract", + get_scatter_nc_field_double(filenames.params, "root_fract", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { vidx = veg_con_map[i].vidx[j]; @@ -1245,7 +1245,7 @@ vic_init(void) // sigma_slope for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veg, "sigma_slope", + get_scatter_nc_field_double(filenames.params, "sigma_slope", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { vidx = veg_con_map[i].vidx[j]; @@ -1262,7 +1262,7 @@ vic_init(void) // lag_one for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veg, "lag_one", + get_scatter_nc_field_double(filenames.params, "lag_one", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { vidx = veg_con_map[i].vidx[j]; @@ -1279,7 +1279,7 @@ vic_init(void) // fetch for (j = 0; j < options.NVEGTYPES; j++) { d3start[0] = j; - get_scatter_nc_field_double(filenames.veg, "fetch", + get_scatter_nc_field_double(filenames.params, "fetch", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { vidx = veg_con_map[i].vidx[j]; @@ -1299,7 +1299,7 @@ vic_init(void) // read_lake parameters if (options.LAKES) { // lake_idx - get_scatter_nc_field_int(filenames.lakeparam, "lake_idx", + get_scatter_nc_field_int(filenames.params, "lake_idx", d2start, d2count, ivar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].lake_idx = ivar[i]; @@ -1316,7 +1316,7 @@ vic_init(void) } // numnod - get_scatter_nc_field_int(filenames.lakeparam, "numnod", + get_scatter_nc_field_int(filenames.params, "numnod", d2start, d2count, ivar); max_numnod = 0; for (i = 0; i < local_domain.ncells_active; i++) { @@ -1346,7 +1346,7 @@ vic_init(void) } // mindepth (minimum depth for which channel outflow occurs) - get_scatter_nc_field_double(filenames.lakeparam, "mindepth", + get_scatter_nc_field_double(filenames.params, "mindepth", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].mindepth = (double) dvar[i]; @@ -1366,7 +1366,7 @@ vic_init(void) } // wfrac - get_scatter_nc_field_double(filenames.lakeparam, "wfrac", + get_scatter_nc_field_double(filenames.params, "wfrac", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].wfrac = (double) dvar[i]; @@ -1385,7 +1385,7 @@ vic_init(void) } // depth_in (initial depth for a cold start) - get_scatter_nc_field_double(filenames.lakeparam, "depth_in", + get_scatter_nc_field_double(filenames.params, "depth_in", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].depth_in = (double) dvar[i]; @@ -1405,7 +1405,7 @@ vic_init(void) } // rpercent - get_scatter_nc_field_double(filenames.lakeparam, "rpercent", + get_scatter_nc_field_double(filenames.params, "rpercent", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].rpercent = (double) dvar[i]; @@ -1437,14 +1437,14 @@ vic_init(void) d3start[0] = j; // basin_depth - get_scatter_nc_field_double(filenames.lakeparam, "basin_depth", + get_scatter_nc_field_double(filenames.params, "basin_depth", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].z[j] = (double) dvar[i]; } // basin_area - get_scatter_nc_field_double(filenames.lakeparam, "basin_area", + get_scatter_nc_field_double(filenames.params, "basin_area", d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].Cl[j] = (double) dvar[i]; @@ -1453,14 +1453,14 @@ vic_init(void) } else { // basin_depth - get_scatter_nc_field_double(filenames.lakeparam, "basin_depth", + get_scatter_nc_field_double(filenames.params, "basin_depth", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].z[0] = (double) dvar[i]; } // basin_area - get_scatter_nc_field_double(filenames.lakeparam, "basin_area", + get_scatter_nc_field_double(filenames.params, "basin_area", d2start, d2count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { lake_con[i].Cl[0] = (double) dvar[i]; diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index d88be8a2e..401f96f09 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -28,8 +28,8 @@ /****************************************************************************** - * @brief Print MPI Error String to LOG_DEST, this function is used by loggers - ******************************************************************************/ +* @brief Print MPI Error String to LOG_DEST, this function is used by loggers +******************************************************************************/ void print_mpi_error_str(int error_code) { @@ -283,17 +283,17 @@ create_MPI_global_struct_type(MPI_Datatype *mpi_type) void create_MPI_filenames_struct_type(MPI_Datatype *mpi_type) { - extern MPI_Comm MPI_COMM_VIC; + extern MPI_Comm MPI_COMM_VIC; - int nitems; // number of elements in struct - int status; - int *blocklengths; - size_t i; - MPI_Aint *offsets; - MPI_Datatype *mpi_types; + int nitems; // number of elements in struct + int status; + int *blocklengths; + size_t i; + MPI_Aint *offsets; + MPI_Datatype *mpi_types; // nitems has to equal the number of elements in filenames_struct - nitems = 14; + nitems = 10; blocklengths = malloc(nitems * sizeof(*blocklengths)); check_alloc_status(blocklengths, "Memory allocation error."); @@ -338,34 +338,18 @@ create_MPI_filenames_struct_type(MPI_Datatype *mpi_type) offsets[i] = offsetof(filenames_struct, init_state); mpi_types[i++] = MPI_CHAR; - // char lakeparam[MAXSTRING]; - offsets[i] = offsetof(filenames_struct, lakeparam); + // char params[MAXSTRING]; + offsets[i] = offsetof(filenames_struct, params); mpi_types[i++] = MPI_CHAR; // char result_dir[MAXSTRING]; offsets[i] = offsetof(filenames_struct, result_dir); mpi_types[i++] = MPI_CHAR; - // char snowband[MAXSTRING]; - offsets[i] = offsetof(filenames_struct, snowband); - mpi_types[i++] = MPI_CHAR; - - // char soil[MAXSTRING]; - offsets[i] = offsetof(filenames_struct, soil); - mpi_types[i++] = MPI_CHAR; - // char statefile[MAXSTRING]; offsets[i] = offsetof(filenames_struct, statefile); mpi_types[i++] = MPI_CHAR; - // char veg[MAXSTRING]; - offsets[i] = offsetof(filenames_struct, veg); - mpi_types[i++] = MPI_CHAR; - - // char veglib[MAXSTRING]; - offsets[i] = offsetof(filenames_struct, veglib); - mpi_types[i++] = MPI_CHAR; - // char log_path[MAXSTRING]; offsets[i] = offsetof(filenames_struct, log_path); mpi_types[i++] = MPI_CHAR; @@ -402,14 +386,14 @@ create_MPI_filenames_struct_type(MPI_Datatype *mpi_type) void create_MPI_location_struct_type(MPI_Datatype *mpi_type) { - extern MPI_Comm MPI_COMM_VIC; + extern MPI_Comm MPI_COMM_VIC; - int nitems; // number of elements in struct - int status; - int *blocklengths; - size_t i; - MPI_Aint *offsets; - MPI_Datatype *mpi_types; + int nitems; // number of elements in struct + int status; + int *blocklengths; + size_t i; + MPI_Aint *offsets; + MPI_Datatype *mpi_types; // nitems has to equal the number of elements in location_struct nitems = 9; @@ -496,14 +480,14 @@ create_MPI_location_struct_type(MPI_Datatype *mpi_type) void create_MPI_option_struct_type(MPI_Datatype *mpi_type) { - extern MPI_Comm MPI_COMM_VIC; + extern MPI_Comm MPI_COMM_VIC; - int nitems; // number of elements in struct - int status; - int *blocklengths; - size_t i; - MPI_Aint *offsets; - MPI_Datatype *mpi_types; + int nitems; // number of elements in struct + int status; + int *blocklengths; + size_t i; + MPI_Aint *offsets; + MPI_Datatype *mpi_types; // nitems has to equal the number of elements in option_struct nitems = 53; @@ -1431,14 +1415,14 @@ create_MPI_param_struct_type(MPI_Datatype *mpi_type) void create_MPI_dmy_struct_type(MPI_Datatype *mpi_type) { - extern MPI_Comm MPI_COMM_VIC; + extern MPI_Comm MPI_COMM_VIC; - int nitems; // number of elements in struct - int status; - int *blocklengths; - size_t i; - MPI_Aint *offsets; - MPI_Datatype *mpi_types; + int nitems; // number of elements in struct + int status; + int *blocklengths; + size_t i; + MPI_Aint *offsets; + MPI_Datatype *mpi_types; // nitems has to equal the number of elements in dmy_struct nitems = 5; @@ -1506,15 +1490,15 @@ create_MPI_dmy_struct_type(MPI_Datatype *mpi_type) void create_MPI_alarm_struct_type(MPI_Datatype *mpi_type) { - extern MPI_Comm MPI_COMM_VIC; + extern MPI_Comm MPI_COMM_VIC; - int nitems; // number of elements in struct - int status; - int *blocklengths; - size_t i; - MPI_Aint *offsets; - MPI_Datatype *mpi_types; - MPI_Datatype mpi_dmy_type; + int nitems; // number of elements in struct + int status; + int *blocklengths; + size_t i; + MPI_Aint *offsets; + MPI_Datatype *mpi_types; + MPI_Datatype mpi_dmy_type; // nitems has to equal the number of elements in alarm_struct nitems = 6; @@ -1738,7 +1722,6 @@ gather_put_nc_field_double(int nc_id, dvar_remapped = malloc(global_domain.ncells_active * sizeof(*dvar_remapped)); check_alloc_status(dvar_remapped, "Memory allocation error."); - } // Gather the results from the nodes, result for the local node is in the // array *var (which is a function argument) @@ -1746,7 +1729,7 @@ gather_put_nc_field_double(int nc_id, dvar_gathered, mpi_map_local_array_sizes, mpi_map_global_array_offsets, MPI_DOUBLE, VIC_MPI_ROOT, MPI_COMM_VIC); -check_mpi_status(status, "MPI error."); + check_mpi_status(status, "MPI error."); if (mpi_rank == VIC_MPI_ROOT) { // remap the array map(sizeof(double), global_domain.ncells_active, NULL, @@ -1806,7 +1789,6 @@ gather_put_nc_field_float(int nc_id, fvar_remapped = malloc(global_domain.ncells_active * sizeof(*fvar_remapped)); check_alloc_status(fvar_remapped, "Memory allocation error."); - } // Gather the results from the nodes, result for the local node is in the // array *var (which is a function argument) @@ -1874,13 +1856,12 @@ gather_put_nc_field_int(int nc_id, ivar_gathered = malloc(global_domain.ncells_active * sizeof(*ivar_gathered)); - check_alloc_status(ivar_gathered, "Memory allocation error."); + check_alloc_status(ivar_gathered, "Memory allocation error."); ivar_remapped = malloc(global_domain.ncells_active * sizeof(*ivar_remapped)); - check_alloc_status(ivar_remapped, "Memory allocation error."); - + check_alloc_status(ivar_remapped, "Memory allocation error."); } // Gather the results from the nodes, result for the local node is in the // array *var (which is a function argument) @@ -1888,7 +1869,7 @@ gather_put_nc_field_int(int nc_id, ivar_gathered, mpi_map_local_array_sizes, mpi_map_global_array_offsets, MPI_INT, VIC_MPI_ROOT, MPI_COMM_VIC); -check_mpi_status(status, "MPI error."); + check_mpi_status(status, "MPI error."); if (mpi_rank == VIC_MPI_ROOT) { // remap the array @@ -1948,13 +1929,12 @@ gather_put_nc_field_short(int nc_id, svar_gathered = malloc(global_domain.ncells_active * sizeof(*svar_gathered)); - check_alloc_status(svar_gathered, "Memory allocation error."); + check_alloc_status(svar_gathered, "Memory allocation error."); svar_remapped = malloc(global_domain.ncells_active * sizeof(*svar_remapped)); - check_alloc_status(svar_remapped, "Memory allocation error."); - + check_alloc_status(svar_remapped, "Memory allocation error."); } // Gather the results from the nodes, result for the local node is in the // array *var (which is a function argument) @@ -1962,7 +1942,7 @@ gather_put_nc_field_short(int nc_id, svar_gathered, mpi_map_local_array_sizes, mpi_map_global_array_offsets, MPI_SHORT, VIC_MPI_ROOT, MPI_COMM_VIC); -check_mpi_status(status, "MPI error."); + check_mpi_status(status, "MPI error."); if (mpi_rank == VIC_MPI_ROOT) { // remap the array @@ -2022,13 +2002,12 @@ gather_put_nc_field_schar(int nc_id, cvar_gathered = malloc(global_domain.ncells_active * sizeof(*cvar_gathered)); - check_alloc_status(cvar_gathered, "Memory allocation error."); + check_alloc_status(cvar_gathered, "Memory allocation error."); cvar_remapped = malloc(global_domain.ncells_active * sizeof(*cvar_remapped)); - check_alloc_status(cvar_remapped, "Memory allocation error."); - + check_alloc_status(cvar_remapped, "Memory allocation error."); } // Gather the results from the nodes, result for the local node is in the // array *var (which is a function argument) @@ -2036,7 +2015,7 @@ gather_put_nc_field_schar(int nc_id, cvar_gathered, mpi_map_local_array_sizes, mpi_map_global_array_offsets, MPI_CHAR, VIC_MPI_ROOT, MPI_COMM_VIC); -check_mpi_status(status, "MPI error."); + check_mpi_status(status, "MPI error."); if (mpi_rank == VIC_MPI_ROOT) { // remap the array @@ -2088,11 +2067,11 @@ get_scatter_nc_field_double(char *nc_name, dvar_filtered = malloc(global_domain.ncells_active * sizeof(*dvar_filtered)); - check_alloc_status(dvar, "Memory allocation error."); + check_alloc_status(dvar, "Memory allocation error."); dvar_mapped = malloc(global_domain.ncells_active * sizeof(*dvar_mapped)); - check_alloc_status(dvar_mapped, "Memory allocation error."); + check_alloc_status(dvar_mapped, "Memory allocation error."); get_nc_field_double(nc_name, var_name, start, count, dvar); // filter the active cells only @@ -2149,11 +2128,11 @@ get_scatter_nc_field_float(char *nc_name, fvar_filtered = malloc(global_domain.ncells_active * sizeof(*fvar_filtered)); - check_alloc_status(fvar_filtered, "Memory allocation error."); + check_alloc_status(fvar_filtered, "Memory allocation error."); fvar_mapped = malloc(global_domain.ncells_active * sizeof(*fvar_mapped)); - check_alloc_status(fvar_mapped, "Memory allocation error."); + check_alloc_status(fvar_mapped, "Memory allocation error."); get_nc_field_float(nc_name, var_name, start, count, fvar); // filter the active cells only @@ -2215,7 +2194,7 @@ get_scatter_nc_field_int(char *nc_name, ivar_mapped = malloc(global_domain.ncells_active * sizeof(*ivar_mapped)); - check_alloc_status(ivar_mapped, "Memory allocation error."); + check_alloc_status(ivar_mapped, "Memory allocation error."); get_nc_field_int(nc_name, var_name, start, count, ivar); // filter the active cells only diff --git a/vic/drivers/shared_image/src/vic_start.c b/vic/drivers/shared_image/src/vic_start.c index 5a356bacc..ace88c4e4 100644 --- a/vic/drivers/shared_image/src/vic_start.c +++ b/vic/drivers/shared_image/src/vic_start.c @@ -63,7 +63,7 @@ vic_start(void) check_mpi_status(status, "MPI error."); // Set Log Destination - setup_logging(mpi_rank); + setup_logging(mpi_rank, filenames.log_path, &(filep.logfile)); if (mpi_rank == VIC_MPI_ROOT) { // set model constants @@ -78,7 +78,7 @@ vic_start(void) // add the number of vegetation type to the location info in the // global domain struct. This just makes life easier - add_nveg_to_global_domain(filenames.veg, &global_domain); + add_nveg_to_global_domain(filenames.params, &global_domain); // decompose the mask mpi_map_decomp_domain(global_domain.ncells_active, mpi_size, @@ -99,18 +99,14 @@ vic_start(void) } // get dimensions (number of vegetation types, soil zones, etc) - options.ROOT_ZONES = get_nc_dimension(filenames.soil, "root_zone"); - options.Nlayer = get_nc_dimension(filenames.soil, "nlayer"); - options.NVEGTYPES = get_nc_dimension(filenames.veg, "veg_class"); - if (options.SNOW_BAND > 1) { - if (options.SNOW_BAND != - get_nc_dimension(filenames.snowband, "snow_band")) { - log_err("Number of snow bands in global file does not " - "match parameter file"); - } + options.ROOT_ZONES = get_nc_dimension(filenames.params, "root_zone"); + options.Nlayer = get_nc_dimension(filenames.params, "nlayer"); + options.NVEGTYPES = get_nc_dimension(filenames.params, "veg_class"); + if (options.SNOW_BAND == SNOW_BAND_TRUE_BUT_UNSET) { + options.SNOW_BAND = get_nc_dimension(filenames.params, "snow_band"); } if (options.LAKES) { - options.NLAKENODES = get_nc_dimension(filenames.lakeparam, + options.NLAKENODES = get_nc_dimension(filenames.params, "lake_node"); } diff --git a/vic/drivers/shared_image/src/vic_write.c b/vic/drivers/shared_image/src/vic_write.c index 001a13ccc..b5f7860da 100644 --- a/vic/drivers/shared_image/src/vic_write.c +++ b/vic/drivers/shared_image/src/vic_write.c @@ -93,7 +93,6 @@ vic_write(stream_struct *stream, // allocate memory for variables to be stored dvar = malloc(local_domain.ncells_active * sizeof(*dvar)); check_alloc_status(dvar, "Memory allocation error"); - } } else if (nc_hist_file->nc_vars[k].nc_type == NC_FLOAT) { @@ -108,7 +107,6 @@ vic_write(stream_struct *stream, // allocate memory for variables to be stored ivar = malloc(local_domain.ncells_active * sizeof(*ivar)); check_alloc_status(ivar, "Memory allocation error"); - } } else if (nc_hist_file->nc_vars[k].nc_type == NC_SHORT) { @@ -116,7 +114,6 @@ vic_write(stream_struct *stream, // allocate memory for variables to be stored svar = malloc(local_domain.ncells_active * sizeof(*svar)); check_alloc_status(svar, "Memory allocation error"); - } } else if (nc_hist_file->nc_vars[k].nc_type == NC_CHAR) { @@ -124,7 +121,6 @@ vic_write(stream_struct *stream, // allocate memory for variables to be stored cvar = malloc(local_domain.ncells_active * sizeof(*cvar)); check_alloc_status(cvar, "Memory allocation error"); - } } else { diff --git a/vic/vic_run/include/vic_log.h b/vic/vic_run/include/vic_log.h index b1c3ac911..819e17457 100644 --- a/vic/vic_run/include/vic_log.h +++ b/vic/vic_run/include/vic_log.h @@ -64,7 +64,7 @@ void finalize_logging(void); void get_logname(const char *path, int id, char *filename); void initialize_log(void); void print_trace(void); -void setup_logging(int id); +void setup_logging(int id, char log_path[], FILE **logfile); // Macros for logging @@ -130,7 +130,10 @@ void setup_logging(int id); #define check(A, M, ...) if (!(A)) {log_err(M, ## __VA_ARGS__); errno = 0; exit( \ EXIT_FAILURE); } -#define check_alloc_status(A, M, ...) if (A == NULL) {log_err(M, ## __VA_ARGS__); errno = 0; exit(EXIT_FAILURE); } +#define check_alloc_status(A, M, \ + ...) if (A == NULL) {log_err(M, ## __VA_ARGS__); \ + errno = 0; exit( \ + EXIT_FAILURE); } #define sentinel(M, ...) {log_err(M, ## __VA_ARGS__); errno = 0; exit( \ EXIT_FAILURE); } From d032d4391cf6610dfe2bbb23bce7d3a099ccbeeb Mon Sep 17 00:00:00 2001 From: yixinmao Date: Wed, 6 Jul 2016 14:24:54 -0700 Subject: [PATCH 02/33] Fix out soil moist bug (#551) * Fixed a bug when outputting `OUT_SOIL_MOIST` and `OUT_SOIL_{LIQ/ICE}_FRAC` --- vic/drivers/shared_all/src/history_metadata.c | 2 ++ vic/drivers/shared_all/src/put_data.c | 8 ++++---- vic/drivers/shared_image/src/vic_nc_info.c | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/vic/drivers/shared_all/src/history_metadata.c b/vic/drivers/shared_all/src/history_metadata.c index 46ece72d1..7bd03b5e1 100644 --- a/vic/drivers/shared_all/src/history_metadata.c +++ b/vic/drivers/shared_all/src/history_metadata.c @@ -1468,6 +1468,8 @@ set_output_met_data_info() out_metadata[OUT_SMFROZFRAC].nelem = options.Nlayer; out_metadata[OUT_SOIL_ICE].nelem = options.Nlayer; out_metadata[OUT_SOIL_LIQ].nelem = options.Nlayer; + out_metadata[OUT_SOIL_ICE_FRAC].nelem = options.Nlayer; + out_metadata[OUT_SOIL_LIQ_FRAC].nelem = options.Nlayer; out_metadata[OUT_SOIL_MOIST].nelem = options.Nlayer; out_metadata[OUT_SOIL_TEMP].nelem = options.Nlayer; out_metadata[OUT_SOIL_TNODE].nelem = options.Nnode; diff --git a/vic/drivers/shared_all/src/put_data.c b/vic/drivers/shared_all/src/put_data.c index cea32433b..8b508955e 100644 --- a/vic/drivers/shared_all/src/put_data.c +++ b/vic/drivers/shared_all/src/put_data.c @@ -491,6 +491,10 @@ put_data(all_vars_struct *all_vars, out_data[OUT_SMLIQFRAC][index] = out_data[OUT_SOIL_LIQ][index] / out_data[OUT_SOIL_MOIST][index]; out_data[OUT_SMFROZFRAC][index] = 1 - out_data[OUT_SMLIQFRAC][index]; + out_data[OUT_SOIL_LIQ_FRAC][index] = out_data[OUT_SOIL_LIQ][index] / (depth[index] * + MM_PER_M); + out_data[OUT_SOIL_ICE_FRAC][index] = out_data[OUT_SOIL_ICE][index] / (depth[index] * + MM_PER_M); } out_data[OUT_DELSOILMOIST][0] -= save_data->total_soil_moist; out_data[OUT_DELSWE][0] = out_data[OUT_SWE][0] + @@ -693,10 +697,6 @@ collect_wb_terms(cell_data_struct cell, out_data[OUT_SOIL_LIQ][index] += tmp_moist * AreaFactor; out_data[OUT_SOIL_ICE][index] += tmp_ice * AreaFactor; - out_data[OUT_SOIL_LIQ][index] = tmp_moist * AreaFactor / depth[index] * - MM_PER_M; - out_data[OUT_SOIL_ICE][index] = tmp_ice * AreaFactor / depth[index] * - MM_PER_M; } out_data[OUT_SOIL_WET][0] += cell.wetness * AreaFactor; out_data[OUT_ROOTMOIST][0] += cell.rootmoist * AreaFactor; diff --git a/vic/drivers/shared_image/src/vic_nc_info.c b/vic/drivers/shared_image/src/vic_nc_info.c index 492bf74cc..bc0c9eaa4 100644 --- a/vic/drivers/shared_image/src/vic_nc_info.c +++ b/vic/drivers/shared_image/src/vic_nc_info.c @@ -58,6 +58,8 @@ set_nc_var_info(unsigned int varid, case OUT_SMFROZFRAC: case OUT_SOIL_ICE: case OUT_SOIL_LIQ: + case OUT_SOIL_ICE_FRAC: + case OUT_SOIL_LIQ_FRAC: case OUT_SOIL_MOIST: case OUT_SOIL_TEMP: nc_var->nc_dims = 4; @@ -133,6 +135,8 @@ set_nc_var_dimids(unsigned int varid, case OUT_SMFROZFRAC: case OUT_SOIL_ICE: case OUT_SOIL_LIQ: + case OUT_SOIL_ICE_FRAC: + case OUT_SOIL_LIQ_FRAC: case OUT_SOIL_MOIST: case OUT_SOIL_TEMP: nc_var->nc_dimids[0] = nc_hist_file->time_dimid; From 4fae68af08df3409a03ec69bc1372817586b770f Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Wed, 6 Jul 2016 15:11:17 -0700 Subject: [PATCH 03/33] rename atmos_data_struct-->force_data_struct --- vic/drivers/cesm/src/cesm_interface_c.c | 2 +- vic/drivers/cesm/src/cesm_put_data.c | 30 ++--- vic/drivers/cesm/src/vic_force.c | 78 ++++++------- .../classic/include/vic_driver_classic.h | 8 +- vic/drivers/classic/src/alloc_atmos.c | 104 +++++++++--------- .../classic/src/print_library_classic.c | 36 +++--- vic/drivers/classic/src/vic_classic.c | 16 +-- vic/drivers/classic/src/vic_force.c | 76 ++++++------- vic/drivers/image/src/vic_force.c | 76 ++++++------- vic/drivers/image/src/vic_image.c | 2 +- .../include/vic_driver_shared_all.h | 8 +- vic/drivers/shared_all/src/compute_treeline.c | 4 +- vic/drivers/shared_all/src/put_data.c | 42 +++---- .../include/vic_driver_shared_image.h | 8 +- vic/drivers/shared_image/src/alloc_atmos.c | 102 ++++++++--------- .../src/print_library_shared_image.c | 38 +++---- vic/drivers/shared_image/src/vic_alloc.c | 12 +- vic/drivers/shared_image/src/vic_finalize.c | 6 +- vic/drivers/shared_image/src/vic_image_run.c | 6 +- .../shared_image/src/vic_init_output.c | 4 +- .../shared_image/src/vic_mpi_support.c | 2 +- vic/vic_run/include/vic_def.h | 8 +- vic/vic_run/include/vic_run.h | 10 +- vic/vic_run/src/calc_surf_energy_bal.c | 10 +- vic/vic_run/src/snow_intercept.c | 14 +-- vic/vic_run/src/solve_snow.c | 16 +-- vic/vic_run/src/surface_fluxes.c | 40 +++---- vic/vic_run/src/vic_run.c | 52 ++++----- 28 files changed, 405 insertions(+), 405 deletions(-) diff --git a/vic/drivers/cesm/src/cesm_interface_c.c b/vic/drivers/cesm/src/cesm_interface_c.c index d3bd5de6b..7cc68c20b 100644 --- a/vic/drivers/cesm/src/cesm_interface_c.c +++ b/vic/drivers/cesm/src/cesm_interface_c.c @@ -31,7 +31,7 @@ size_t current; size_t *filter_active_cells = NULL; size_t *mpi_map_mapping_array = NULL; all_vars_struct *all_vars = NULL; -atmos_data_struct *atmos = NULL; +force_data_struct *force = NULL; x2l_data_struct *x2l_vic = NULL; l2x_data_struct *l2x_vic = NULL; dmy_struct dmy_current; diff --git a/vic/drivers/cesm/src/cesm_put_data.c b/vic/drivers/cesm/src/cesm_put_data.c index a2696d47b..71b5a94fe 100644 --- a/vic/drivers/cesm/src/cesm_put_data.c +++ b/vic/drivers/cesm/src/cesm_put_data.c @@ -33,7 +33,7 @@ void vic_cesm_put_data() { extern all_vars_struct *all_vars; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern dmy_struct dmy_current; extern domain_struct local_domain; extern soil_con_struct *soil_con; @@ -140,26 +140,26 @@ vic_cesm_put_data() // 2m reference temperature // CESM units: K - l2x_vic[i].l2x_Sl_tref += AreaFactor * atmos->air_temp[NR]; + l2x_vic[i].l2x_Sl_tref += AreaFactor * force->air_temp[NR]; // 2m reference specific humidity // CESM units: g/g l2x_vic[i].l2x_Sl_qref += AreaFactor * CONST_EPS * - atmos->vp[NR] / atmos->pressure[NR]; + force->vp[NR] / force->pressure[NR]; // Albedo Note: VIC does not partition its albedo, all returned // values will be the same // albedo: direct, visible // CESM units: unitless - // atmos->shortwave is the incoming shortwave (+ down) - // atmos->NetShortAtmos net shortwave flux (+ down) - // SWup = atmos->shortwave[NR] - energy.NetShortAtmos + // force->shortwave is the incoming shortwave (+ down) + // force->NetShortAtmos net shortwave flux (+ down) + // SWup = force->shortwave[NR] - energy.NetShortAtmos // Set the albedo to zero for the case where there is no shortwave down - if (atmos->shortwave[NR] > 0.) { + if (force->shortwave[NR] > 0.) { albedo = AreaFactor * - (atmos->shortwave[NR] - energy.NetShortAtmos) / - atmos->shortwave[NR]; + (force->shortwave[NR] - energy.NetShortAtmos) / + force->shortwave[NR]; } else { albedo = 0.; @@ -184,7 +184,7 @@ vic_cesm_put_data() // 10m wind // CESM units: m/s - l2x_vic[i].l2x_Sl_u10 += AreaFactor * atmos->wind[NR]; + l2x_vic[i].l2x_Sl_u10 += AreaFactor * force->wind[NR]; // dry deposition velocities (optional) // CESM units: ? @@ -230,13 +230,13 @@ vic_cesm_put_data() // wind stress, zonal // CESM units: N m-2 - wind_stress_x = -1 * atmos[i].density[NR] * + wind_stress_x = -1 * force[i].density[NR] * x2l_vic[i].x2l_Sa_u / aero_resist; l2x_vic[i].l2x_Fall_taux += AreaFactor * wind_stress_x; // wind stress, meridional // CESM units: N m-2 - wind_stress_y = -1 * atmos[i].density[NR] * + wind_stress_y = -1 * force[i].density[NR] * x2l_vic[i].x2l_Sa_v / aero_resist; l2x_vic[i].l2x_Fall_tauy += AreaFactor * wind_stress_y; @@ -245,7 +245,7 @@ vic_cesm_put_data() wind_stress = sqrt(pow(wind_stress_x, 2) + pow(wind_stress_y, 2)); l2x_vic[i].l2x_Sl_fv += AreaFactor * - (wind_stress / atmos[i].density[NR]); + (wind_stress / force[i].density[NR]); // latent heat flux // CESM units: W m-2 @@ -259,7 +259,7 @@ vic_cesm_put_data() // upward longwave heat flux // CESM units: W m-2 l2x_vic[i].l2x_Fall_lwup += AreaFactor * - (atmos->longwave[NR] - + (force->longwave[NR] - energy.NetLongAtmos); // evaporation water flux @@ -278,7 +278,7 @@ vic_cesm_put_data() // heat flux shortwave net l2x_vic[i].l2x_Fall_swnet += AreaFactor * - (atmos->shortwave[NR] - + (force->shortwave[NR] - energy.NetShortAtmos); // co2 flux **For testing set to 0 diff --git a/vic/drivers/cesm/src/vic_force.c b/vic/drivers/cesm/src/vic_force.c index 1811c1caa..e9c680442 100644 --- a/vic/drivers/cesm/src/vic_force.c +++ b/vic/drivers/cesm/src/vic_force.c @@ -1,7 +1,7 @@ /****************************************************************************** * @section DESCRIPTION * - * Read atmospheric forcing data. + * Unpack forcing data. * * @section LICENSE * @@ -35,7 +35,7 @@ vic_force(void) extern size_t NF; extern size_t NR; extern size_t current; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern x2l_data_struct *x2l_vic; extern dmy_struct dmy_current; extern domain_struct global_domain; @@ -72,7 +72,7 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: K // VIC units: C - atmos[i].air_temp[j] = x2l_vic[i].x2l_Sa_tbot - CONST_TKFRZ; + force[i].air_temp[j] = x2l_vic[i].x2l_Sa_tbot - CONST_TKFRZ; } } @@ -82,7 +82,7 @@ vic_force(void) // CESM units: km m-2 s-1 // VIC units: mm / timestep // Note: VIC does not use liquid/solid precip partitioning - atmos[i].prec[j] = (x2l_vic[i].x2l_Faxa_rainc + + force[i].prec[j] = (x2l_vic[i].x2l_Faxa_rainc + x2l_vic[i].x2l_Faxa_rainl + x2l_vic[i].x2l_Faxa_snowc + x2l_vic[i].x2l_Faxa_snowl) * @@ -96,7 +96,7 @@ vic_force(void) // CESM units: W m-2 // VIC units: W m-2 // Note: VIC does not use partitioned shortwave fluxes. - atmos[i].shortwave[j] = (x2l_vic[i].x2l_Faxa_swndr + + force[i].shortwave[j] = (x2l_vic[i].x2l_Faxa_swndr + x2l_vic[i].x2l_Faxa_swvdr + x2l_vic[i].x2l_Faxa_swndf + x2l_vic[i].x2l_Faxa_swvdf); @@ -108,7 +108,7 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: W m-2 // VIC units: W m-2 - atmos[i].longwave[j] = x2l_vic[i].x2l_Faxa_lwdn; + force[i].longwave[j] = x2l_vic[i].x2l_Faxa_lwdn; } } @@ -118,7 +118,7 @@ vic_force(void) // CESM units: m s-1 // VIC units: m s-1 // Note: VIC does not use partitioned wind speeds - atmos[i].wind[j] = sqrt(pow(x2l_vic[i].x2l_Sa_u, 2) + + force[i].wind[j] = sqrt(pow(x2l_vic[i].x2l_Sa_u, 2) + pow(x2l_vic[i].x2l_Sa_v, 2)); } } @@ -128,7 +128,7 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: Pa // VIC units: kPa - atmos[i].pressure[j] = x2l_vic[i].x2l_Sa_pbot / PA_PER_KPA; + force[i].pressure[j] = x2l_vic[i].x2l_Sa_pbot / PA_PER_KPA; } } @@ -137,8 +137,8 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: shum is specific humidity (g/g) // VIC units: kPa - atmos[i].vp[j] = q_to_vp(x2l_vic[i].x2l_Sa_shum, - atmos[i].pressure[j]); + force[i].vp[j] = q_to_vp(x2l_vic[i].x2l_Sa_shum, + force[i].pressure[j]); } } @@ -148,14 +148,14 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: n/a (calculated from SW fluxes) // VIC units: fraction - if (atmos[i].shortwave[j] != 0.) { - atmos[i].fdir[j] = (x2l_vic[i].x2l_Faxa_swndr + + if (force[i].shortwave[j] != 0.) { + force[i].fdir[j] = (x2l_vic[i].x2l_Faxa_swndr + x2l_vic[i].x2l_Faxa_swvdr) / (x2l_vic[i].x2l_Faxa_swndf + x2l_vic[i].x2l_Faxa_swvdf); } else { - atmos[i].fdir[j] = 0.; + force[i].fdir[j] = 0.; } } } @@ -165,14 +165,14 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: 1e-6 mol/mol // VIC units: mol CO2/ mol air - atmos[i].Catm[j] = 1e6 * x2l_vic[i].x2l_Sa_co2prog; + force[i].Catm[j] = 1e6 * x2l_vic[i].x2l_Sa_co2prog; } } // Cosine of solar zenith angle for (j = 0; j < NF; j++) { for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].coszen[j] = compute_coszen( + force[i].coszen[j] = compute_coszen( local_domain.locations[i].latitude, local_domain.locations[i].longitude, soil_con[i].time_zone_lng, dmy_current.day_in_year, @@ -187,7 +187,7 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: kg m-2 s-1 // VIC units: mm - atmos[i].channel_in[j] = x2l_vic[i].x2l_Flrr_flood * + force[i].channel_in[j] = x2l_vic[i].x2l_Flrr_flood * global_param.snow_dt; } } @@ -204,49 +204,49 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { for (j = 0; j < NF; j++) { // vapor pressure deficit - atmos[i].vpd[j] = svp(atmos[i].air_temp[j]) - atmos[i].vp[j]; + force[i].vpd[j] = svp(force[i].air_temp[j]) - force[i].vp[j]; // photosynthetically active radiation // TODO: Add CARBON_SW2PAR back to the parameters structure - // atmos[i].par[j] = param.CARBON_SW2PAR * atmos[i].shortwave[j]; + // force[i].par[j] = param.CARBON_SW2PAR * force[i].shortwave[j]; // air density - atmos[i].density[j] = air_density(atmos[i].air_temp[j], - atmos[i].pressure[j]); + force[i].density[j] = air_density(force[i].air_temp[j], + force[i].pressure[j]); // snow flag - atmos[i].snowflag[j] = will_it_snow(&(atmos[i].air_temp[j]), + force[i].snowflag[j] = will_it_snow(&(force[i].air_temp[j]), t_offset, param.SNOW_MAX_SNOW_TEMP, - &(atmos[i].prec[j]), 1); + &(force[i].prec[j]), 1); } } // Put average value in NR field for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].air_temp[NR] = average(atmos[i].air_temp, NF); + force[i].air_temp[NR] = average(force[i].air_temp, NF); // For precipitation put total - atmos[i].prec[NR] = average(atmos[i].prec, NF) * NF; - atmos[i].shortwave[NR] = average(atmos[i].shortwave, NF); - atmos[i].longwave[NR] = average(atmos[i].longwave, NF); - atmos[i].pressure[NR] = average(atmos[i].pressure, NF); - atmos[i].wind[NR] = average(atmos[i].wind, NF); - atmos[i].vp[NR] = average(atmos[i].vp, NF); - atmos[i].vpd[NR] = (svp(atmos[i].air_temp[NR]) - atmos[i].vp[NR]); - atmos[i].density[NR] = air_density(atmos[i].air_temp[NR], - atmos[i].pressure[NR]); - atmos[i].snowflag[NR] = will_it_snow(atmos[i].air_temp, t_offset, + force[i].prec[NR] = average(force[i].prec, NF) * NF; + force[i].shortwave[NR] = average(force[i].shortwave, NF); + force[i].longwave[NR] = average(force[i].longwave, NF); + force[i].pressure[NR] = average(force[i].pressure, NF); + force[i].wind[NR] = average(force[i].wind, NF); + force[i].vp[NR] = average(force[i].vp, NF); + force[i].vpd[NR] = (svp(force[i].air_temp[NR]) - force[i].vp[NR]); + force[i].density[NR] = air_density(force[i].air_temp[NR], + force[i].pressure[NR]); + force[i].snowflag[NR] = will_it_snow(force[i].air_temp, t_offset, param.SNOW_MAX_SNOW_TEMP, - atmos[i].prec, NF); + force[i].prec, NF); // Optional inputs if (options.LAKES) { - atmos[i].channel_in[NR] = average(atmos[i].channel_in, NF) * NF; + force[i].channel_in[NR] = average(force[i].channel_in, NF) * NF; } if (options.CARBON) { - atmos[i].Catm[NR] = average(atmos[i].Catm, NF); - atmos[i].fdir[NR] = average(atmos[i].fdir, NF); - atmos[i].par[NR] = average(atmos[i].par, NF); + force[i].Catm[NR] = average(force[i].Catm, NF); + force[i].fdir[NR] = average(force[i].fdir, NF); + force[i].par[NR] = average(force[i].par, NF); // for coszen, use value at noon - atmos[i].coszen[NR] = compute_coszen( + force[i].coszen[NR] = compute_coszen( local_domain.locations[i].latitude, local_domain.locations[i].longitude, soil_con[i].time_zone_lng, dmy_current.day_in_year, SEC_PER_DAY / 2); diff --git a/vic/drivers/classic/include/vic_driver_classic.h b/vic/drivers/classic/include/vic_driver_classic.h index 4d66c7865..0b3b74a20 100644 --- a/vic/drivers/classic/include/vic_driver_classic.h +++ b/vic/drivers/classic/include/vic_driver_classic.h @@ -71,7 +71,7 @@ typedef struct { char log_path[MAXSTRING]; /**< Location to write log file to*/ } filenames_struct; -void alloc_atmos(int, atmos_data_struct **); +void alloc_atmos(int, force_data_struct **); void alloc_veg_hist(int nrecs, int nveg, veg_hist_struct ***veg_hist); void calc_netlongwave(double *, double, double, double); double calc_netshort(double, int, double, double *); @@ -80,7 +80,7 @@ bool check_save_state_flag(dmy_struct *, size_t); FILE *check_state_file(char *, size_t, size_t, int *); void close_files(filep_struct *filep, stream_struct **streams); void compute_cell_area(soil_con_struct *); -void free_atmos(int nrecs, atmos_data_struct **atmos); +void free_atmos(int nrecs, force_data_struct **force); void free_veg_hist(int nrecs, int nveg, veg_hist_struct ***veg_hist); void free_veglib(veg_lib_struct **); double get_dist(double lat1, double long1, double lat2, double long2); @@ -93,7 +93,7 @@ void make_in_and_outfiles(filep_struct *filep, filenames_struct *filenames, soil_con_struct *soil, stream_struct **streams, dmy_struct *dmy); FILE *open_state_file(global_param_struct *, filenames_struct, size_t, size_t); -void print_atmos_data(atmos_data_struct *atmos, size_t nr); +void print_atmos_data(force_data_struct *force, size_t nr); void parse_output_info(FILE *gp, stream_struct **output_streams, dmy_struct *dmy_current); void read_atmos_data(FILE *, global_param_struct, int, int, double **, @@ -106,7 +106,7 @@ void read_snowband(FILE *, soil_con_struct *); soil_con_struct read_soilparam(FILE *, char *, char *); veg_lib_struct *read_veglib(FILE *, size_t *); veg_con_struct *read_vegparam(FILE *, int, size_t); -void vic_force(atmos_data_struct *, dmy_struct *, FILE **, veg_con_struct *, +void vic_force(force_data_struct *, dmy_struct *, FILE **, veg_con_struct *, veg_hist_struct **, soil_con_struct *); void vic_populate_model_state(all_vars_struct *, filep_struct, size_t, soil_con_struct *, veg_con_struct *, diff --git a/vic/drivers/classic/src/alloc_atmos.c b/vic/drivers/classic/src/alloc_atmos.c index 1a61b337b..c41584040 100644 --- a/vic/drivers/classic/src/alloc_atmos.c +++ b/vic/drivers/classic/src/alloc_atmos.c @@ -31,50 +31,50 @@ *****************************************************************************/ void alloc_atmos(int nrecs, - atmos_data_struct **atmos) + force_data_struct **force) { extern option_struct options; int i; - *atmos = calloc(nrecs, sizeof(atmos_data_struct)); - check_alloc_status(*atmos, "Memory allocation error."); + *force = calloc(nrecs, sizeof(force_data_struct)); + check_alloc_status(*force, "Memory allocation error."); for (i = 0; i < nrecs; i++) { - (*atmos)[i].air_temp = calloc(NR + 1, sizeof(*(*atmos)[i].air_temp)); - check_alloc_status((*atmos)[i].air_temp, "Memory allocation error."); - (*atmos)[i].density = calloc(NR + 1, sizeof(*(*atmos)[i].density)); - check_alloc_status((*atmos)[i].density, "Memory allocation error."); - (*atmos)[i].longwave = calloc(NR + 1, sizeof(*(*atmos)[i].longwave)); - check_alloc_status((*atmos)[i].longwave, "Memory allocation error."); - (*atmos)[i].prec = calloc(NR + 1, sizeof(*(*atmos)[i].prec)); - check_alloc_status((*atmos)[i].prec, "Memory allocation error."); - (*atmos)[i].pressure = calloc(NR + 1, sizeof(*(*atmos)[i].pressure)); - check_alloc_status((*atmos)[i].pressure, "Memory allocation error."); - (*atmos)[i].shortwave = calloc(NR + 1, sizeof(*(*atmos)[i].shortwave)); - check_alloc_status((*atmos)[i].shortwave, "Memory allocation error."); - (*atmos)[i].snowflag = calloc(NR + 1, sizeof(*(*atmos)[i].snowflag)); - check_alloc_status((*atmos)[i].snowflag, "Memory allocation error."); - (*atmos)[i].vp = calloc(NR + 1, sizeof(*(*atmos)[i].vp)); - check_alloc_status((*atmos)[i].vp, "Memory allocation error."); - (*atmos)[i].vpd = calloc(NR + 1, sizeof(*(*atmos)[i].vpd)); - check_alloc_status((*atmos)[i].vpd, "Memory allocation error."); - (*atmos)[i].wind = calloc(NR + 1, sizeof(*(*atmos)[i].wind)); - check_alloc_status((*atmos)[i].wind, "Memory allocation error."); + (*force)[i].air_temp = calloc(NR + 1, sizeof(*(*force)[i].air_temp)); + check_alloc_status((*force)[i].air_temp, "Memory allocation error."); + (*force)[i].density = calloc(NR + 1, sizeof(*(*force)[i].density)); + check_alloc_status((*force)[i].density, "Memory allocation error."); + (*force)[i].longwave = calloc(NR + 1, sizeof(*(*force)[i].longwave)); + check_alloc_status((*force)[i].longwave, "Memory allocation error."); + (*force)[i].prec = calloc(NR + 1, sizeof(*(*force)[i].prec)); + check_alloc_status((*force)[i].prec, "Memory allocation error."); + (*force)[i].pressure = calloc(NR + 1, sizeof(*(*force)[i].pressure)); + check_alloc_status((*force)[i].pressure, "Memory allocation error."); + (*force)[i].shortwave = calloc(NR + 1, sizeof(*(*force)[i].shortwave)); + check_alloc_status((*force)[i].shortwave, "Memory allocation error."); + (*force)[i].snowflag = calloc(NR + 1, sizeof(*(*force)[i].snowflag)); + check_alloc_status((*force)[i].snowflag, "Memory allocation error."); + (*force)[i].vp = calloc(NR + 1, sizeof(*(*force)[i].vp)); + check_alloc_status((*force)[i].vp, "Memory allocation error."); + (*force)[i].vpd = calloc(NR + 1, sizeof(*(*force)[i].vpd)); + check_alloc_status((*force)[i].vpd, "Memory allocation error."); + (*force)[i].wind = calloc(NR + 1, sizeof(*(*force)[i].wind)); + check_alloc_status((*force)[i].wind, "Memory allocation error."); if (options.LAKES) { - (*atmos)[i].channel_in = - calloc(NR + 1, sizeof(*(*atmos)[i].channel_in)); - check_alloc_status((*atmos)[i].channel_in, + (*force)[i].channel_in = + calloc(NR + 1, sizeof(*(*force)[i].channel_in)); + check_alloc_status((*force)[i].channel_in, "Memory allocation error."); } if (options.CARBON) { - (*atmos)[i].Catm = calloc(NR + 1, sizeof(*(*atmos)[i].Catm)); - check_alloc_status((*atmos)[i].Catm, "Memory allocation error."); - (*atmos)[i].coszen = calloc(NR + 1, sizeof(*(*atmos)[i].coszen)); - check_alloc_status((*atmos)[i].coszen, "Memory allocation error."); - (*atmos)[i].fdir = calloc(NR + 1, sizeof(*(*atmos)[i].fdir)); - check_alloc_status((*atmos)[i].fdir, "Memory allocation error."); - (*atmos)[i].par = calloc(NR + 1, sizeof(*(*atmos)[i].par)); - check_alloc_status((*atmos)[i].par, "Memory allocation error."); + (*force)[i].Catm = calloc(NR + 1, sizeof(*(*force)[i].Catm)); + check_alloc_status((*force)[i].Catm, "Memory allocation error."); + (*force)[i].coszen = calloc(NR + 1, sizeof(*(*force)[i].coszen)); + check_alloc_status((*force)[i].coszen, "Memory allocation error."); + (*force)[i].fdir = calloc(NR + 1, sizeof(*(*force)[i].fdir)); + check_alloc_status((*force)[i].fdir, "Memory allocation error."); + (*force)[i].par = calloc(NR + 1, sizeof(*(*force)[i].par)); + check_alloc_status((*force)[i].par, "Memory allocation error."); } } } @@ -84,36 +84,36 @@ alloc_atmos(int nrecs, *****************************************************************************/ void free_atmos(int nrecs, - atmos_data_struct **atmos) + force_data_struct **force) { extern option_struct options; int i; - if (*atmos == NULL) { + if (*force == NULL) { return; } for (i = 0; i < nrecs; i++) { - free((*atmos)[i].air_temp); - free((*atmos)[i].density); - free((*atmos)[i].longwave); - free((*atmos)[i].prec); - free((*atmos)[i].pressure); - free((*atmos)[i].shortwave); - free((*atmos)[i].snowflag); - free((*atmos)[i].vp); - free((*atmos)[i].vpd); - free((*atmos)[i].wind); + free((*force)[i].air_temp); + free((*force)[i].density); + free((*force)[i].longwave); + free((*force)[i].prec); + free((*force)[i].pressure); + free((*force)[i].shortwave); + free((*force)[i].snowflag); + free((*force)[i].vp); + free((*force)[i].vpd); + free((*force)[i].wind); if (options.LAKES) { - free((*atmos)[i].channel_in); + free((*force)[i].channel_in); } if (options.CARBON) { - free((*atmos)[i].Catm); - free((*atmos)[i].coszen); - free((*atmos)[i].fdir); - free((*atmos)[i].par); + free((*force)[i].Catm); + free((*force)[i].coszen); + free((*force)[i].fdir); + free((*force)[i].par); } } - free(*atmos); + free(*force); } diff --git a/vic/drivers/classic/src/print_library_classic.c b/vic/drivers/classic/src/print_library_classic.c index 7aad3bc9c..d53fdfe33 100644 --- a/vic/drivers/classic/src/print_library_classic.c +++ b/vic/drivers/classic/src/print_library_classic.c @@ -30,7 +30,7 @@ * @brief Print atmos data structure. *****************************************************************************/ void -print_atmos_data(atmos_data_struct *atmos, +print_atmos_data(force_data_struct *force, size_t nr) { extern option_struct options; @@ -39,90 +39,90 @@ print_atmos_data(atmos_data_struct *atmos, fprintf(LOG_DEST, "atmos_data :\n"); fprintf(LOG_DEST, "\tair_temp :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->air_temp[i]); + fprintf(LOG_DEST, "\t%.4f", force->air_temp[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tdensity :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->density[i]); + fprintf(LOG_DEST, "\t%.4f", force->density[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tlongwave :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->longwave[i]); + fprintf(LOG_DEST, "\t%.4f", force->longwave[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tout_prec :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->out_prec); + fprintf(LOG_DEST, "\t%.4f", force->out_prec); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tout_rain :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->out_rain); + fprintf(LOG_DEST, "\t%.4f", force->out_rain); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tout_snow :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->out_snow); + fprintf(LOG_DEST, "\t%.4f", force->out_snow); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tprec :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->prec[i]); + fprintf(LOG_DEST, "\t%.4f", force->prec[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tpressure :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->pressure[i]); + fprintf(LOG_DEST, "\t%.4f", force->pressure[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tshortwave :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->shortwave[i]); + fprintf(LOG_DEST, "\t%.4f", force->shortwave[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tsnowflag :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%d\n", atmos->snowflag[i]); + fprintf(LOG_DEST, "\t%d\n", force->snowflag[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tvp :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->vp[i]); + fprintf(LOG_DEST, "\t%.4f", force->vp[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tvpd :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->vpd[i]); + fprintf(LOG_DEST, "\t%.4f", force->vpd[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\twind :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->wind[i]); + fprintf(LOG_DEST, "\t%.4f", force->wind[i]); } fprintf(LOG_DEST, "\n"); if (options.LAKES) { fprintf(LOG_DEST, "\tchannel_in:"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->channel_in[i]); + fprintf(LOG_DEST, "\t%.4f", force->channel_in[i]); } fprintf(LOG_DEST, "\n"); } if (options.CARBON) { fprintf(LOG_DEST, "\tCatm :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->Catm[i]); + fprintf(LOG_DEST, "\t%.4f", force->Catm[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tfdir :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->fdir[i]); + fprintf(LOG_DEST, "\t%.4f", force->fdir[i]); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\tpar :"); for (i = 0; i <= nr; i++) { - fprintf(LOG_DEST, "\t%.4f", atmos->par[i]); + fprintf(LOG_DEST, "\t%.4f", force->par[i]); } fprintf(LOG_DEST, "\n"); } diff --git a/vic/drivers/classic/src/vic_classic.c b/vic/drivers/classic/src/vic_classic.c index 262c3dbf7..09a7d4bf8 100644 --- a/vic/drivers/classic/src/vic_classic.c +++ b/vic/drivers/classic/src/vic_classic.c @@ -68,7 +68,7 @@ main(int argc, int ErrorFlag; size_t streamnum; dmy_struct *dmy; - atmos_data_struct *atmos; + force_data_struct *force; veg_hist_struct **veg_hist; veg_con_struct *veg_con; soil_con_struct soil_con; @@ -130,8 +130,8 @@ main(int argc, /** Initialize Parameters **/ cellnum = -1; - /** allocate memory for the atmos_data_struct **/ - alloc_atmos(global_param.nrecs, &atmos); + /** allocate memory for the force_data_struct **/ + alloc_atmos(global_param.nrecs, &force); /** Initial state **/ startrec = 0; @@ -190,7 +190,7 @@ main(int argc, Have not Been Specifically Set **************************************************/ - vic_force(atmos, dmy, filep.forcing, veg_con, veg_hist, &soil_con); + vic_force(force, dmy, filep.forcing, veg_con, veg_hist, &soil_con); /************************************************** Initialize Energy Balance and Snow Variables @@ -200,7 +200,7 @@ main(int argc, &soil_con, veg_con, lake_con); /** Initialize the storage terms in the water and energy balances **/ - initialize_save_data(&all_vars, &atmos[0], &soil_con, veg_con, + initialize_save_data(&all_vars, &force[0], &soil_con, veg_con, veg_lib, &lake_con, out_data[0], &save_data); /****************************************** @@ -223,14 +223,14 @@ main(int argc, /************************************************** Compute cell physics for 1 timestep **************************************************/ - ErrorFlag = vic_run(&atmos[rec], &all_vars, + ErrorFlag = vic_run(&force[rec], &all_vars, &(dmy[rec]), &global_param, &lake_con, &soil_con, veg_con, veg_lib); /************************************************** Calculate cell average values for current time step **************************************************/ - put_data(&all_vars, &atmos[rec], &soil_con, veg_con, veg_lib, + put_data(&all_vars, &force[rec], &soil_con, veg_con, veg_lib, &lake_con, out_data[0], &save_data); for (streamnum = 0; @@ -290,7 +290,7 @@ main(int argc, } /* End Grid Loop */ /** cleanup **/ - free_atmos(global_param.nrecs, &atmos); + free_atmos(global_param.nrecs, &force); free_dmy(&dmy); free_streams(&streams); free_out_data(1, out_data); // 1 is for the number of gridcells, 1 in classic driver diff --git a/vic/drivers/classic/src/vic_force.c b/vic/drivers/classic/src/vic_force.c index 99c374832..6f361f06f 100644 --- a/vic/drivers/classic/src/vic_force.c +++ b/vic/drivers/classic/src/vic_force.c @@ -31,7 +31,7 @@ * @brief Initialize atmospheric variables for the model and snow time steps. *****************************************************************************/ void -vic_force(atmos_data_struct *atmos, +vic_force(force_data_struct *force, dmy_struct *dmy, FILE **infile, veg_con_struct *veg_con, @@ -125,48 +125,48 @@ vic_force(atmos_data_struct *atmos, for (i = 0; i < NF; i++) { uidx = rec * NF + i; // temperature in Celsius - atmos[rec].air_temp[i] = forcing_data[AIR_TEMP][uidx]; + force[rec].air_temp[i] = forcing_data[AIR_TEMP][uidx]; // precipitation in mm/period - atmos[rec].prec[i] = forcing_data[PREC][uidx]; + force[rec].prec[i] = forcing_data[PREC][uidx]; // downward shortwave in W/m2 - atmos[rec].shortwave[i] = forcing_data[SWDOWN][uidx]; + force[rec].shortwave[i] = forcing_data[SWDOWN][uidx]; // downward longwave in W/m2 - atmos[rec].longwave[i] = forcing_data[LWDOWN][uidx]; + force[rec].longwave[i] = forcing_data[LWDOWN][uidx]; // pressure in Pa - atmos[rec].pressure[i] = forcing_data[PRESSURE][uidx] * PA_PER_KPA; + force[rec].pressure[i] = forcing_data[PRESSURE][uidx] * PA_PER_KPA; // vapor pressure in Pa - atmos[rec].vp[i] = forcing_data[VP][uidx] * PA_PER_KPA; + force[rec].vp[i] = forcing_data[VP][uidx] * PA_PER_KPA; // vapor pressure deficit in Pa - atmos[rec].vpd[i] = svp(atmos[rec].air_temp[i]) - atmos[rec].vp[i]; + force[rec].vpd[i] = svp(force[rec].air_temp[i]) - force[rec].vp[i]; // air density in kg/m3 - atmos[rec].density[i] = air_density(atmos[rec].air_temp[i], - atmos[rec].pressure[i]); + force[rec].density[i] = air_density(force[rec].air_temp[i], + force[rec].pressure[i]); // wind speed in m/s - atmos[rec].wind[i] = forcing_data[WIND][uidx]; + force[rec].wind[i] = forcing_data[WIND][uidx]; // snow flag - atmos[rec].snowflag[i] = will_it_snow(&(atmos[rec].air_temp[i]), + force[rec].snowflag[i] = will_it_snow(&(force[rec].air_temp[i]), t_offset, param.SNOW_MAX_SNOW_TEMP, - &(atmos[rec].prec[i]), 1); + &(force[rec].prec[i]), 1); // Optional inputs if (options.LAKES) { // Channel inflow from upstream (into lake) if (param_set.TYPE[CHANNEL_IN].SUPPLIED) { - atmos[rec].channel_in[i] = forcing_data[CHANNEL_IN][uidx]; + force[rec].channel_in[i] = forcing_data[CHANNEL_IN][uidx]; } else { - atmos[rec].channel_in[i] = 0; + force[rec].channel_in[i] = 0; } } if (options.CARBON) { // Atmospheric CO2 concentration - atmos[rec].Catm[i] = forcing_data[CATM][uidx]; + force[rec].Catm[i] = forcing_data[CATM][uidx]; // Fraction of shortwave that is direct - atmos[rec].fdir[i] = forcing_data[FDIR][uidx]; + force[rec].fdir[i] = forcing_data[FDIR][uidx]; // photosynthetically active radiation - atmos[rec].par[i] = forcing_data[PAR][uidx]; + force[rec].par[i] = forcing_data[PAR][uidx]; // Cosine of solar zenith angle - atmos[rec].coszen[i] = compute_coszen(soil_con->lat, + force[rec].coszen[i] = compute_coszen(soil_con->lat, soil_con->lng, soil_con->time_zone_lng, dmy[rec].day_in_year, @@ -174,32 +174,32 @@ vic_force(atmos_data_struct *atmos, } } if (NF > 1) { - atmos[rec].air_temp[NR] = average(atmos[rec].air_temp, NF); + force[rec].air_temp[NR] = average(force[rec].air_temp, NF); // For precipitation put total - atmos[rec].prec[NR] = average(atmos[rec].prec, NF) * NF; - atmos[rec].shortwave[NR] = average(atmos[rec].shortwave, NF); - atmos[rec].longwave[NR] = average(atmos[rec].longwave, NF); - atmos[rec].pressure[NR] = average(atmos[rec].pressure, NF); - atmos[rec].vp[NR] = average(atmos[rec].vp, NF); - atmos[rec].vpd[NR] = average(atmos[rec].vpd, NF); - atmos[rec].density[NR] = average(atmos[rec].density, NF); - atmos[rec].wind[NR] = average(atmos[rec].wind, NF); - atmos[rec].snowflag[NR] = false; + force[rec].prec[NR] = average(force[rec].prec, NF) * NF; + force[rec].shortwave[NR] = average(force[rec].shortwave, NF); + force[rec].longwave[NR] = average(force[rec].longwave, NF); + force[rec].pressure[NR] = average(force[rec].pressure, NF); + force[rec].vp[NR] = average(force[rec].vp, NF); + force[rec].vpd[NR] = average(force[rec].vpd, NF); + force[rec].density[NR] = average(force[rec].density, NF); + force[rec].wind[NR] = average(force[rec].wind, NF); + force[rec].snowflag[NR] = false; for (i = 0; i < NF; i++) { - if (atmos[rec].snowflag[i] == true) { - atmos[rec].snowflag[NR] = true; + if (force[rec].snowflag[i] == true) { + force[rec].snowflag[NR] = true; } } if (options.LAKES) { - atmos[rec].channel_in[NR] = - average(atmos[rec].channel_in, NF) * NF; + force[rec].channel_in[NR] = + average(force[rec].channel_in, NF) * NF; } if (options.CARBON) { - atmos[rec].Catm[NR] = average(atmos[rec].Catm, NF); - atmos[rec].fdir[NR] = average(atmos[rec].fdir, NF); - atmos[rec].par[NR] = average(atmos[rec].par, NF); + force[rec].Catm[NR] = average(force[rec].Catm, NF); + force[rec].fdir[NR] = average(force[rec].fdir, NF); + force[rec].par[NR] = average(force[rec].par, NF); // for coszen, use value at noon - atmos[rec].coszen[NR] = compute_coszen(soil_con->lat, + force[rec].coszen[NR] = compute_coszen(soil_con->lat, soil_con->lng, soil_con->time_zone_lng, dmy[rec].day_in_year, @@ -305,7 +305,7 @@ vic_force(atmos_data_struct *atmos, if (options.COMPUTE_TREELINE) { if (!(options.JULY_TAVG_SUPPLIED && avgJulyAirTemp == -999)) { - compute_treeline(atmos, dmy, avgJulyAirTemp, Tfactor, + compute_treeline(force, dmy, avgJulyAirTemp, Tfactor, AboveTreeLine); } } diff --git a/vic/drivers/image/src/vic_force.c b/vic/drivers/image/src/vic_force.c index 5b34f60e4..baa6f2a6c 100644 --- a/vic/drivers/image/src/vic_force.c +++ b/vic/drivers/image/src/vic_force.c @@ -35,7 +35,7 @@ vic_force(void) extern size_t NF; extern size_t NR; extern size_t current; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern dmy_struct *dmy; extern domain_struct global_domain; extern domain_struct local_domain; @@ -91,7 +91,7 @@ vic_force(void) param_set.TYPE[AIR_TEMP].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].air_temp[j] = (double) dvar[i]; + force[i].air_temp[j] = (double) dvar[i]; } } @@ -103,7 +103,7 @@ vic_force(void) param_set.TYPE[PREC].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].prec[j] = (double) dvar[i]; + force[i].prec[j] = (double) dvar[i]; } } @@ -115,7 +115,7 @@ vic_force(void) param_set.TYPE[SWDOWN].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].shortwave[j] = (double) dvar[i]; + force[i].shortwave[j] = (double) dvar[i]; } } @@ -127,7 +127,7 @@ vic_force(void) param_set.TYPE[LWDOWN].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].longwave[j] = (double) dvar[i]; + force[i].longwave[j] = (double) dvar[i]; } } @@ -139,7 +139,7 @@ vic_force(void) param_set.TYPE[WIND].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].wind[j] = (double) dvar[i]; + force[i].wind[j] = (double) dvar[i]; } } @@ -151,7 +151,7 @@ vic_force(void) param_set.TYPE[VP].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].vp[j] = (double) dvar[i]; + force[i].vp[j] = (double) dvar[i]; } } @@ -163,7 +163,7 @@ vic_force(void) param_set.TYPE[PRESSURE].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].pressure[j] = (double) dvar[i]; + force[i].pressure[j] = (double) dvar[i]; } } // Optional inputs @@ -176,7 +176,7 @@ vic_force(void) d3start, d3count, dvar); for (j = 0; j < NF; j++) { for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].channel_in[j] = (double) dvar[i]; + force[i].channel_in[j] = (double) dvar[i]; } } } @@ -189,13 +189,13 @@ vic_force(void) param_set.TYPE[CATM].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].Catm[j] = (double) dvar[i]; + force[i].Catm[j] = (double) dvar[i]; } } // Cosine of solar zenith angle for (j = 0; j < NF; j++) { for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].coszen[j] = compute_coszen( + force[i].coszen[j] = compute_coszen( local_domain.locations[i].latitude, local_domain.locations[i].longitude, soil_con[i].time_zone_lng, dmy[current].day_in_year, @@ -210,7 +210,7 @@ vic_force(void) param_set.TYPE[FDIR].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].fdir[j] = (double) dvar[i]; + force[i].fdir[j] = (double) dvar[i]; } } // Photosynthetically active radiation @@ -221,7 +221,7 @@ vic_force(void) param_set.TYPE[PAR].varname, d3start, d3count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].par[j] = (double) dvar[i]; + force[i].par[j] = (double) dvar[i]; } } } @@ -358,22 +358,22 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { for (j = 0; j < NF; j++) { // temperature in Celsius - atmos[i].air_temp[j] -= CONST_TKFRZ; + force[i].air_temp[j] -= CONST_TKFRZ; // precipitation in mm/period - atmos[i].prec[j] *= global_param.snow_dt; + force[i].prec[j] *= global_param.snow_dt; // pressure in Pa // vapor pressure in Pa (we read specific humidity in kg/kg) - atmos[i].vp[j] = q_to_vp(atmos[i].vp[j], atmos[i].pressure[j]); + force[i].vp[j] = q_to_vp(force[i].vp[j], force[i].pressure[j]); // vapor pressure deficit in Pa - atmos[i].vpd[j] = svp(atmos[i].air_temp[j]) - atmos[i].vp[j]; + force[i].vpd[j] = svp(force[i].air_temp[j]) - force[i].vp[j]; // air density in kg/m3 - atmos[i].density[j] = air_density(atmos[i].air_temp[j], - atmos[i].pressure[j]); + force[i].density[j] = air_density(force[i].air_temp[j], + force[i].pressure[j]); // snow flag - atmos[i].snowflag[j] = will_it_snow(&(atmos[i].air_temp[j]), + force[i].snowflag[j] = will_it_snow(&(force[i].air_temp[j]), t_offset[i], param.SNOW_MAX_SNOW_TEMP, - &(atmos[i].prec[j]), 1); + &(force[i].prec[j]), 1); } // Check on fcanopy for (v = 0; v < options.NVEGTYPES; v++) { @@ -398,20 +398,20 @@ vic_force(void) // Put average value in NR field for (i = 0; i < local_domain.ncells_active; i++) { - atmos[i].air_temp[NR] = average(atmos[i].air_temp, NF); + force[i].air_temp[NR] = average(force[i].air_temp, NF); // For precipitation put total - atmos[i].prec[NR] = average(atmos[i].prec, NF) * NF; - atmos[i].shortwave[NR] = average(atmos[i].shortwave, NF); - atmos[i].longwave[NR] = average(atmos[i].longwave, NF); - atmos[i].pressure[NR] = average(atmos[i].pressure, NF); - atmos[i].wind[NR] = average(atmos[i].wind, NF); - atmos[i].vp[NR] = average(atmos[i].vp, NF); - atmos[i].vpd[NR] = (svp(atmos[i].air_temp[NR]) - atmos[i].vp[NR]); - atmos[i].density[NR] = air_density(atmos[i].air_temp[NR], - atmos[i].pressure[NR]); - atmos[i].snowflag[NR] = will_it_snow(atmos[i].air_temp, t_offset[i], + force[i].prec[NR] = average(force[i].prec, NF) * NF; + force[i].shortwave[NR] = average(force[i].shortwave, NF); + force[i].longwave[NR] = average(force[i].longwave, NF); + force[i].pressure[NR] = average(force[i].pressure, NF); + force[i].wind[NR] = average(force[i].wind, NF); + force[i].vp[NR] = average(force[i].vp, NF); + force[i].vpd[NR] = (svp(force[i].air_temp[NR]) - force[i].vp[NR]); + force[i].density[NR] = air_density(force[i].air_temp[NR], + force[i].pressure[NR]); + force[i].snowflag[NR] = will_it_snow(force[i].air_temp, t_offset[i], param.SNOW_MAX_SNOW_TEMP, - atmos[i].prec, NF); + force[i].prec, NF); for (v = 0; v < options.NVEGTYPES; v++) { vidx = veg_con_map[i].vidx[v]; @@ -433,14 +433,14 @@ vic_force(void) // Optional inputs if (options.LAKES) { - atmos[i].channel_in[NR] = average(atmos[i].channel_in, NF) * NF; + force[i].channel_in[NR] = average(force[i].channel_in, NF) * NF; } if (options.CARBON) { - atmos[i].Catm[NR] = average(atmos[i].Catm, NF); - atmos[i].fdir[NR] = average(atmos[i].fdir, NF); - atmos[i].par[NR] = average(atmos[i].par, NF); + force[i].Catm[NR] = average(force[i].Catm, NF); + force[i].fdir[NR] = average(force[i].fdir, NF); + force[i].par[NR] = average(force[i].par, NF); // for coszen, use value at noon - atmos[i].coszen[NR] = compute_coszen( + force[i].coszen[NR] = compute_coszen( local_domain.locations[i].latitude, local_domain.locations[i].longitude, soil_con[i].time_zone_lng, dmy[current].day_in_year, SEC_PER_DAY / 2); diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index b73d326f7..deac3d431 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -31,7 +31,7 @@ size_t current; size_t *filter_active_cells = NULL; size_t *mpi_map_mapping_array = NULL; all_vars_struct *all_vars = NULL; -atmos_data_struct *atmos = NULL; +force_data_struct *force = NULL; dmy_struct *dmy = NULL; filenames_struct filenames; filep_struct filep; diff --git a/vic/drivers/shared_all/include/vic_driver_shared_all.h b/vic/drivers/shared_all/include/vic_driver_shared_all.h index 24d661e89..f220d6000 100644 --- a/vic/drivers/shared_all/include/vic_driver_shared_all.h +++ b/vic/drivers/shared_all/include/vic_driver_shared_all.h @@ -536,7 +536,7 @@ typedef struct { * routines. *****************************************************************************/ typedef struct { - atmos_data_struct *atmos; + force_data_struct *force; double dt; energy_bal_struct *energy; size_t rec; @@ -570,7 +570,7 @@ void collect_wb_terms(cell_data_struct, veg_var_struct, snow_data_struct, void compute_derived_state_vars(all_vars_struct *, soil_con_struct *, veg_con_struct *); void compute_lake_params(lake_con_struct *, soil_con_struct); -void compute_treeline(atmos_data_struct *, dmy_struct *, double, double *, +void compute_treeline(force_data_struct *, dmy_struct *, double, double *, bool *); size_t count_force_vars(FILE *gp); void count_nstreams_nvars(FILE *gp, size_t *nstreams, size_t nvars[]); @@ -607,7 +607,7 @@ void initialize_energy(energy_bal_struct **energy, size_t nveg); void initialize_global(void); void initialize_options(void); void initialize_parameters(void); -void initialize_save_data(all_vars_struct *all_vars, atmos_data_struct *atmos, +void initialize_save_data(all_vars_struct *all_vars, force_data_struct *force, soil_con_struct *soil_con, veg_con_struct *veg_con, veg_lib_struct *veg_lib, lake_con_struct *lake_con, double **out_data, save_data_struct *save_data); @@ -632,7 +632,7 @@ void num2date(double origin, double time_value, double tzoffset, FILE *open_file(char string[], char type[]); void parse_nc_time_units(char *nc_unit_chars, unsigned short int *units, dmy_struct *dmy); -void put_data(all_vars_struct *, atmos_data_struct *, soil_con_struct *, +void put_data(all_vars_struct *, force_data_struct *, soil_con_struct *, veg_con_struct *, veg_lib_struct *veg_lib, lake_con_struct *, double **out_data, save_data_struct *); void print_alarm(alarm_struct *alarm); diff --git a/vic/drivers/shared_all/src/compute_treeline.c b/vic/drivers/shared_all/src/compute_treeline.c index 60b5c0ce2..0881ec940 100644 --- a/vic/drivers/shared_all/src/compute_treeline.c +++ b/vic/drivers/shared_all/src/compute_treeline.c @@ -41,7 +41,7 @@ * @brief Compute treeline. *****************************************************************************/ void -compute_treeline(atmos_data_struct *atmos, +compute_treeline(force_data_struct *force, dmy_struct *dmy, double avgJulyAirTemp, double *Tfactor, @@ -74,7 +74,7 @@ compute_treeline(atmos_data_struct *atmos, MonthCnt = 0; while (dmy[rec].month == 7) { for (i = 0; i < NF; i++) { - MonthSum += atmos[rec].air_temp[i]; + MonthSum += force[rec].air_temp[i]; MonthCnt++; } rec++; diff --git a/vic/drivers/shared_all/src/put_data.c b/vic/drivers/shared_all/src/put_data.c index 8b508955e..3e63780bd 100644 --- a/vic/drivers/shared_all/src/put_data.c +++ b/vic/drivers/shared_all/src/put_data.c @@ -33,7 +33,7 @@ *****************************************************************************/ void put_data(all_vars_struct *all_vars, - atmos_data_struct *atmos, + force_data_struct *force, soil_con_struct *soil_con, veg_con_struct *veg_con, veg_lib_struct *veg_lib, @@ -129,31 +129,31 @@ put_data(all_vars_struct *all_vars, zero_output_list(out_data); // Set output versions of input forcings - out_data[OUT_AIR_TEMP][0] = atmos->air_temp[NR]; - out_data[OUT_DENSITY][0] = atmos->density[NR]; - out_data[OUT_LWDOWN][0] = atmos->longwave[NR]; - out_data[OUT_PREC][0] = atmos->out_prec; // mm over grid cell - out_data[OUT_PRESSURE][0] = atmos->pressure[NR] / PA_PER_KPA; - out_data[OUT_QAIR][0] = CONST_EPS * atmos->vp[NR] / - atmos->pressure[NR]; - out_data[OUT_RAINF][0] = atmos->out_rain; // mm over grid cell - out_data[OUT_REL_HUMID][0] = FRACT_TO_PERCENT * atmos->vp[NR] / - (atmos->vp[NR] + atmos->vpd[NR]); + out_data[OUT_AIR_TEMP][0] = force->air_temp[NR]; + out_data[OUT_DENSITY][0] = force->density[NR]; + out_data[OUT_LWDOWN][0] = force->longwave[NR]; + out_data[OUT_PREC][0] = force->out_prec; // mm over grid cell + out_data[OUT_PRESSURE][0] = force->pressure[NR] / PA_PER_KPA; + out_data[OUT_QAIR][0] = CONST_EPS * force->vp[NR] / + force->pressure[NR]; + out_data[OUT_RAINF][0] = force->out_rain; // mm over grid cell + out_data[OUT_REL_HUMID][0] = FRACT_TO_PERCENT * force->vp[NR] / + (force->vp[NR] + force->vpd[NR]); if (options.LAKES && lake_con->Cl[0] > 0) { - out_data[OUT_LAKE_CHAN_IN][0] = atmos->channel_in[NR]; // mm over grid cell + out_data[OUT_LAKE_CHAN_IN][0] = force->channel_in[NR]; // mm over grid cell } else { out_data[OUT_LAKE_CHAN_IN][0] = 0; } - out_data[OUT_SWDOWN][0] = atmos->shortwave[NR]; - out_data[OUT_SNOWF][0] = atmos->out_snow; // mm over grid cell - out_data[OUT_VP][0] = atmos->vp[NR] / PA_PER_KPA; - out_data[OUT_VPD][0] = atmos->vpd[NR] / PA_PER_KPA; - out_data[OUT_WIND][0] = atmos->wind[NR]; + out_data[OUT_SWDOWN][0] = force->shortwave[NR]; + out_data[OUT_SNOWF][0] = force->out_snow; // mm over grid cell + out_data[OUT_VP][0] = force->vp[NR] / PA_PER_KPA; + out_data[OUT_VPD][0] = force->vpd[NR] / PA_PER_KPA; + out_data[OUT_WIND][0] = force->wind[NR]; if (options.CARBON) { - out_data[OUT_CATM][0] = atmos->Catm[NR] / PPM_to_MIXRATIO; - out_data[OUT_FDIR][0] = atmos->fdir[NR]; - out_data[OUT_PAR][0] = atmos->par[NR]; + out_data[OUT_CATM][0] = force->Catm[NR] / PPM_to_MIXRATIO; + out_data[OUT_FDIR][0] = force->fdir[NR]; + out_data[OUT_PAR][0] = force->par[NR]; } else { out_data[OUT_CATM][0] = MISSING; @@ -1048,7 +1048,7 @@ collect_eb_terms(energy_bal_struct energy, *****************************************************************************/ void initialize_save_data(all_vars_struct *all_vars, - atmos_data_struct *atmos, + force_data_struct *atmos, soil_con_struct *soil_con, veg_con_struct *veg_con, veg_lib_struct *veg_lib, diff --git a/vic/drivers/shared_image/include/vic_driver_shared_image.h b/vic/drivers/shared_image/include/vic_driver_shared_image.h index fcacfba2c..596e0ed0c 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -158,7 +158,7 @@ typedef struct { * @brief file structures *****************************************************************************/ typedef struct { - FILE *forcing[MAX_FORCE_FILES]; /**< atmospheric forcing data files */ + FILE *forcing[MAX_FORCE_FILES]; /**< forcing data files */ FILE *globalparam; /**< global parameters file */ FILE *constants; /**< model constants parameter file */ FILE *domain; /**< domain file */ @@ -185,12 +185,12 @@ typedef struct { } filenames_struct; void add_nveg_to_global_domain(char *nc_name, domain_struct *global_domain); -void alloc_atmos(atmos_data_struct *atmos); +void alloc_force(force_data_struct *force); void alloc_veg_hist(veg_hist_struct *veg_hist); double air_density(double t, double p); double average(double *ar, size_t n); void check_init_state_file(void); -void free_atmos(atmos_data_struct *atmos); +void free_force(force_data_struct *force); void free_veg_hist(veg_hist_struct *veg_hist); void get_domain_type(char *cmdstr); size_t get_global_domain(char *fname, domain_struct *global_domain); @@ -225,7 +225,7 @@ void initialize_soil_con(soil_con_struct *soil_con); void initialize_veg_con(veg_con_struct *veg_con); void parse_output_info(FILE *gp, stream_struct **output_streams, dmy_struct *dmy_current); -void print_atmos_data(atmos_data_struct *atmos); +void print_force_data(force_data_struct *force); void print_domain(domain_struct *domain, bool print_loc); void print_location(location_struct *location); void print_nc_file(nc_file_struct *nc); diff --git a/vic/drivers/shared_image/src/alloc_atmos.c b/vic/drivers/shared_image/src/alloc_atmos.c index 3e060358f..7438704e4 100644 --- a/vic/drivers/shared_image/src/alloc_atmos.c +++ b/vic/drivers/shared_image/src/alloc_atmos.c @@ -1,7 +1,7 @@ /****************************************************************************** * @section DESCRIPTION * - * Allocate and free memory for the atmos data struct + * Allocate and free memory for the force data struct * * @section LICENSE * @@ -27,91 +27,91 @@ #include /****************************************************************************** - * @brief Allocate memory for the atmos data structure. + * @brief Allocate memory for the force data structure. *****************************************************************************/ void -alloc_atmos(atmos_data_struct *atmos) +alloc_force(force_data_struct *force) { extern option_struct options; - atmos->air_temp = calloc(NR + 1, sizeof(*(atmos->air_temp))); - check_alloc_status(atmos->air_temp, "Memory allocation error."); + force->air_temp = calloc(NR + 1, sizeof(*(force->air_temp))); + check_alloc_status(force->air_temp, "Memory allocation error."); - atmos->density = calloc(NR + 1, sizeof(*(atmos->density))); - check_alloc_status(atmos->density, "Memory allocation error."); + force->density = calloc(NR + 1, sizeof(*(force->density))); + check_alloc_status(force->density, "Memory allocation error."); - atmos->longwave = calloc(NR + 1, sizeof(*(atmos->longwave))); - check_alloc_status(atmos->longwave, "Memory allocation error."); + force->longwave = calloc(NR + 1, sizeof(*(force->longwave))); + check_alloc_status(force->longwave, "Memory allocation error."); - atmos->prec = calloc(NR + 1, sizeof(*(atmos->prec))); - check_alloc_status(atmos->prec, "Memory allocation error."); + force->prec = calloc(NR + 1, sizeof(*(force->prec))); + check_alloc_status(force->prec, "Memory allocation error."); - atmos->pressure = calloc(NR + 1, sizeof(*(atmos->pressure))); - check_alloc_status(atmos->pressure, "Memory allocation error."); + force->pressure = calloc(NR + 1, sizeof(*(force->pressure))); + check_alloc_status(force->pressure, "Memory allocation error."); - atmos->shortwave = calloc(NR + 1, sizeof(*(atmos->shortwave))); - check_alloc_status(atmos->shortwave, "Memory allocation error."); + force->shortwave = calloc(NR + 1, sizeof(*(force->shortwave))); + check_alloc_status(force->shortwave, "Memory allocation error."); - atmos->snowflag = calloc(NR + 1, sizeof(*(atmos->snowflag))); - check_alloc_status(atmos->snowflag, "Memory allocation error."); + force->snowflag = calloc(NR + 1, sizeof(*(force->snowflag))); + check_alloc_status(force->snowflag, "Memory allocation error."); - atmos->vp = calloc(NR + 1, sizeof(*(atmos->vp))); - check_alloc_status(atmos->vp, "Memory allocation error."); + force->vp = calloc(NR + 1, sizeof(*(force->vp))); + check_alloc_status(force->vp, "Memory allocation error."); - atmos->vpd = calloc(NR + 1, sizeof(*(atmos->vpd))); - check_alloc_status(atmos->vpd, "Memory allocation error."); + force->vpd = calloc(NR + 1, sizeof(*(force->vpd))); + check_alloc_status(force->vpd, "Memory allocation error."); - atmos->wind = calloc(NR + 1, sizeof(*(atmos->wind))); - check_alloc_status(atmos->wind, "Memory allocation error."); + force->wind = calloc(NR + 1, sizeof(*(force->wind))); + check_alloc_status(force->wind, "Memory allocation error."); if (options.LAKES) { - atmos->channel_in = calloc(NR + 1, sizeof(*(atmos->channel_in))); - check_alloc_status(atmos->channel_in, "Memory allocation error."); + force->channel_in = calloc(NR + 1, sizeof(*(force->channel_in))); + check_alloc_status(force->channel_in, "Memory allocation error."); } if (options.CARBON) { - atmos->Catm = calloc(NR + 1, sizeof(*(atmos->Catm))); - check_alloc_status(atmos->Catm, "Memory allocation error."); + force->Catm = calloc(NR + 1, sizeof(*(force->Catm))); + check_alloc_status(force->Catm, "Memory allocation error."); - atmos->coszen = calloc(NR + 1, sizeof(*(atmos->coszen))); - check_alloc_status(atmos->coszen, "Memory allocation error."); + force->coszen = calloc(NR + 1, sizeof(*(force->coszen))); + check_alloc_status(force->coszen, "Memory allocation error."); - atmos->fdir = calloc(NR + 1, sizeof(*(atmos->fdir))); - check_alloc_status(atmos->fdir, "Memory allocation error."); + force->fdir = calloc(NR + 1, sizeof(*(force->fdir))); + check_alloc_status(force->fdir, "Memory allocation error."); - atmos->par = calloc(NR + 1, sizeof(*(atmos->par))); - check_alloc_status(atmos->par, "Memory allocation error."); + force->par = calloc(NR + 1, sizeof(*(force->par))); + check_alloc_status(force->par, "Memory allocation error."); } } /****************************************************************************** - * @brief Free memory for the atmos data structure. + * @brief Free memory for the force data structure. *****************************************************************************/ void -free_atmos(atmos_data_struct *atmos) +free_force(force_data_struct *force) { extern option_struct options; - if (atmos == NULL) { + if (force == NULL) { return; } - free(atmos->air_temp); - free(atmos->density); - free(atmos->longwave); - free(atmos->prec); - free(atmos->pressure); - free(atmos->shortwave); - free(atmos->snowflag); - free(atmos->vp); - free(atmos->vpd); - free(atmos->wind); + free(force->air_temp); + free(force->density); + free(force->longwave); + free(force->prec); + free(force->pressure); + free(force->shortwave); + free(force->snowflag); + free(force->vp); + free(force->vpd); + free(force->wind); if (options.LAKES) { - free(atmos->channel_in); + free(force->channel_in); } if (options.CARBON) { - free(atmos->Catm); - free(atmos->coszen); - free(atmos->fdir); - free(atmos->par); + free(force->Catm); + free(force->coszen); + free(force->fdir); + free(force->par); } } diff --git a/vic/drivers/shared_image/src/print_library_shared_image.c b/vic/drivers/shared_image/src/print_library_shared_image.c index 359bb1984..c3d33fb0b 100644 --- a/vic/drivers/shared_image/src/print_library_shared_image.c +++ b/vic/drivers/shared_image/src/print_library_shared_image.c @@ -30,31 +30,31 @@ * @brief Print atmos data structure. *****************************************************************************/ void -print_atmos_data(atmos_data_struct *atmos) +print_force_data(force_data_struct *force) { extern option_struct options; - fprintf(LOG_DEST, "atmos_data :\n"); - fprintf(LOG_DEST, "\tair_temp : %.4f\n", atmos->air_temp[0]); - fprintf(LOG_DEST, "\tdensity : %.4f\n", atmos->density[0]); - fprintf(LOG_DEST, "\tlongwave : %.4f\n", atmos->longwave[0]); - fprintf(LOG_DEST, "\tout_prec : %.4f\n", atmos->out_prec); - fprintf(LOG_DEST, "\tout_rain : %.4f\n", atmos->out_rain); - fprintf(LOG_DEST, "\tout_snow : %.4f\n", atmos->out_snow); - fprintf(LOG_DEST, "\tprec : %.4f\n", atmos->prec[0]); - fprintf(LOG_DEST, "\tpressure : %.4f\n", atmos->pressure[0]); - fprintf(LOG_DEST, "\tshortwave : %.4f\n", atmos->shortwave[0]); - fprintf(LOG_DEST, "\tsnowflag : %d\n", atmos->snowflag[0]); - fprintf(LOG_DEST, "\tvp : %.4f\n", atmos->vp[0]); - fprintf(LOG_DEST, "\tvpd : %.4f\n", atmos->vpd[0]); - fprintf(LOG_DEST, "\twind : %.4f\n", atmos->wind[0]); + fprintf(LOG_DEST, "force_data :\n"); + fprintf(LOG_DEST, "\tair_temp : %.4f\n", force->air_temp[0]); + fprintf(LOG_DEST, "\tdensity : %.4f\n", force->density[0]); + fprintf(LOG_DEST, "\tlongwave : %.4f\n", force->longwave[0]); + fprintf(LOG_DEST, "\tout_prec : %.4f\n", force->out_prec); + fprintf(LOG_DEST, "\tout_rain : %.4f\n", force->out_rain); + fprintf(LOG_DEST, "\tout_snow : %.4f\n", force->out_snow); + fprintf(LOG_DEST, "\tprec : %.4f\n", force->prec[0]); + fprintf(LOG_DEST, "\tpressure : %.4f\n", force->pressure[0]); + fprintf(LOG_DEST, "\tshortwave : %.4f\n", force->shortwave[0]); + fprintf(LOG_DEST, "\tsnowflag : %d\n", force->snowflag[0]); + fprintf(LOG_DEST, "\tvp : %.4f\n", force->vp[0]); + fprintf(LOG_DEST, "\tvpd : %.4f\n", force->vpd[0]); + fprintf(LOG_DEST, "\twind : %.4f\n", force->wind[0]); if (options.LAKES) { - fprintf(LOG_DEST, "\tchannel_in: %.4f\n", atmos->channel_in[0]); + fprintf(LOG_DEST, "\tchannel_in: %.4f\n", force->channel_in[0]); } if (options.CARBON) { - fprintf(LOG_DEST, "\tCatm : %.4f\n", atmos->Catm[0]); - fprintf(LOG_DEST, "\tfdir : %.4f\n", atmos->fdir[0]); - fprintf(LOG_DEST, "\tpar : %.4f\n", atmos->par[0]); + fprintf(LOG_DEST, "\tCatm : %.4f\n", force->Catm[0]); + fprintf(LOG_DEST, "\tfdir : %.4f\n", force->fdir[0]); + fprintf(LOG_DEST, "\tpar : %.4f\n", force->par[0]); } } diff --git a/vic/drivers/shared_image/src/vic_alloc.c b/vic/drivers/shared_image/src/vic_alloc.c index da4220261..9c4a0b2cc 100644 --- a/vic/drivers/shared_image/src/vic_alloc.c +++ b/vic/drivers/shared_image/src/vic_alloc.c @@ -33,7 +33,7 @@ void vic_alloc(void) { extern all_vars_struct *all_vars; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern domain_struct local_domain; extern option_struct options; extern double ***out_data; @@ -47,9 +47,9 @@ vic_alloc(void) size_t i; size_t j; - // allocate memory for atmos structure - atmos = malloc(local_domain.ncells_active * sizeof(*atmos)); - check_alloc_status(atmos, "Memory allocation error."); + // allocate memory for force structure + force = malloc(local_domain.ncells_active * sizeof(*force)); + check_alloc_status(force, "Memory allocation error."); // allocate memory for veg_hist structure veg_hist = malloc(local_domain.ncells_active * sizeof(*veg_hist)); @@ -91,8 +91,8 @@ vic_alloc(void) // allocate memory for individual grid cells for (i = 0; i < local_domain.ncells_active; i++) { - // atmos allocation - allocate enough memory for NR+1 steps - alloc_atmos(&(atmos[i])); + // force allocation - allocate enough memory for NR+1 steps + alloc_force(&(force[i])); // snow band allocation soil_con[i].AreaFract = calloc(options.SNOW_BAND, diff --git a/vic/drivers/shared_image/src/vic_finalize.c b/vic/drivers/shared_image/src/vic_finalize.c index b06cb272c..fdcb1e8f6 100644 --- a/vic/drivers/shared_image/src/vic_finalize.c +++ b/vic/drivers/shared_image/src/vic_finalize.c @@ -35,7 +35,7 @@ vic_finalize(void) extern size_t *filter_active_cells; extern size_t *mpi_map_mapping_array; extern all_vars_struct *all_vars; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern domain_struct global_domain; extern domain_struct local_domain; extern filep_struct filep; @@ -80,7 +80,7 @@ vic_finalize(void) } for (i = 0; i < local_domain.ncells_active; i++) { - free_atmos(&(atmos[i])); + free_force(&(force[i])); free(soil_con[i].AreaFract); free(soil_con[i].BandElev); free(soil_con[i].Tfactor); @@ -104,7 +104,7 @@ vic_finalize(void) free_streams(&output_streams); free_out_data(local_domain.ncells_active, out_data); - free(atmos); + free(force); free(soil_con); free(veg_con_map); free(veg_con); diff --git a/vic/drivers/shared_image/src/vic_image_run.c b/vic/drivers/shared_image/src/vic_image_run.c index 14f35347f..dd6f734af 100644 --- a/vic/drivers/shared_image/src/vic_image_run.c +++ b/vic/drivers/shared_image/src/vic_image_run.c @@ -34,7 +34,7 @@ vic_image_run(dmy_struct *dmy_current) { extern size_t current; extern all_vars_struct *all_vars; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern domain_struct local_domain; extern option_struct options; extern global_param_struct global_param; @@ -60,9 +60,9 @@ vic_image_run(dmy_struct *dmy_current) local_domain.locations[i].io_idx, dmy_str); update_step_vars(&(all_vars[i]), veg_con[i], veg_hist[i]); - vic_run(&(atmos[i]), &(all_vars[i]), dmy_current, &global_param, + vic_run(&(force[i]), &(all_vars[i]), dmy_current, &global_param, &lake_con, &(soil_con[i]), veg_con[i], veg_lib[i]); - put_data(&(all_vars[i]), &(atmos[i]), &(soil_con[i]), veg_con[i], + put_data(&(all_vars[i]), &(force[i]), &(soil_con[i]), veg_con[i], veg_lib[i], &lake_con, out_data[i], &(save_data[i])); } for (i = 0; i < options.Noutstreams; i++) { diff --git a/vic/drivers/shared_image/src/vic_init_output.c b/vic/drivers/shared_image/src/vic_init_output.c index 97bc7e7d5..73c6d1e93 100644 --- a/vic/drivers/shared_image/src/vic_init_output.c +++ b/vic/drivers/shared_image/src/vic_init_output.c @@ -36,7 +36,7 @@ void vic_init_output(dmy_struct *dmy_current) { extern all_vars_struct *all_vars; - extern atmos_data_struct *atmos; + extern force_data_struct *force; extern domain_struct local_domain; extern filep_struct filep; extern MPI_Comm MPI_COMM_VIC; @@ -66,7 +66,7 @@ vic_init_output(dmy_struct *dmy_current) // initialize the save data structures for (i = 0; i < local_domain.ncells_active; i++) { - initialize_save_data(&(all_vars[i]), &(atmos[i]), &(soil_con[i]), + initialize_save_data(&(all_vars[i]), &(force[i]), &(soil_con[i]), veg_con[i], veg_lib[i], &lake_con, out_data[i], &(save_data[i])); } diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index 401f96f09..ff1d06529 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -2231,7 +2231,7 @@ get_scatter_nc_field_int(char *nc_name, size_t *filter_active_cells = NULL; size_t *mpi_map_mapping_array = NULL; // all_vars_struct *all_vars = NULL; -// atmos_data_struct *atmos = NULL; +// force_data_struct *force = NULL; // dmy_struct *dmy = NULL; filenames_struct filenames; filep_struct filep; diff --git a/vic/vic_run/include/vic_def.h b/vic/vic_run/include/vic_def.h index b593fa33d..d8a462d63 100644 --- a/vic/vic_run/include/vic_def.h +++ b/vic/vic_run/include/vic_def.h @@ -83,9 +83,9 @@ #define min(a, b) (a < b) ? a : b #define max(a, b) (a > b) ? a : b -extern size_t NR; /**< array index for atmos struct that indicates +extern size_t NR; /**< array index for force struct that indicates the model step avarage or sum */ -extern size_t NF; /**< array index loop counter limit for atmos +extern size_t NF; /**< array index loop counter limit for force struct that indicates the SNOW_STEP values */ char vic_run_ref_str[MAXSTRING]; @@ -706,7 +706,7 @@ typedef struct { } veg_hist_struct; /****************************************************************************** - * @brief This structure stores the atmospheric forcing data for each model + * @brief This structure stores the forcing data for each model * time step for a single grid cell. Each array stores the values for the * SNOW_STEPs during the current model step and the value for the entire model * step. The latter is referred to by array[NR]. Looping over the SNOW_STEPs @@ -734,7 +734,7 @@ typedef struct { double *vp; /**< atmospheric vapor pressure (kPa) */ double *vpd; /**< atmospheric vapor pressure deficit (kPa) */ double *wind; /**< wind speed (m/s) */ -} atmos_data_struct; +} force_data_struct; /****************************************************************************** * @brief This structure stores information about the time and date of the diff --git a/vic/vic_run/include/vic_run.h b/vic/vic_run/include/vic_run.h index 1a0eb8a5e..a812fa744 100644 --- a/vic/vic_run/include/vic_run.h +++ b/vic/vic_run/include/vic_run.h @@ -78,7 +78,7 @@ double calc_surf_energy_bal(double, double, double, double, double, double, double, double *, double *, double, double *, double *, int, int, size_t, size_t, double, size_t, unsigned short int, int, unsigned short int, - double *, double *, atmos_data_struct *, + double *, double *, force_data_struct *, dmy_struct *, energy_bal_struct *, layer_data_struct *, snow_data_struct *, soil_con_struct *, veg_var_struct *); @@ -243,7 +243,7 @@ int snow_intercept(double, double, double, double, double, double, double, double *, bool *, unsigned int *, double *, double *, double *, double *, double *, double *, double *, int, int, int, int, int, unsigned short int, double *, double *, - atmos_data_struct *, layer_data_struct *, soil_con_struct *, + force_data_struct *, layer_data_struct *, soil_con_struct *, veg_var_struct *); int snow_melt(double, double, double, double, double *, double, double *, double, double, double, double, double, double, double, double, @@ -271,7 +271,7 @@ double solve_snow(char, double, double, double, double, double, double, double, double *, double *, double *, double *, double *, double *, int, size_t, unsigned short int, unsigned short int, double, size_t, int, int *, double *, double *, dmy_struct *, - atmos_data_struct *, energy_bal_struct *, layer_data_struct *, + force_data_struct *, energy_bal_struct *, layer_data_struct *, snow_data_struct *, soil_con_struct *, veg_var_struct *); double solve_surf_energy_bal(double Tsurf, ...); int solve_T_profile(double *, double *, char *, unsigned int *, double *, @@ -293,7 +293,7 @@ int surface_fluxes(bool, double, double, double, double, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, double *, size_t, size_t, unsigned short int, double, unsigned short int, - unsigned short int, atmos_data_struct *, dmy_struct *, + unsigned short int, force_data_struct *, dmy_struct *, energy_bal_struct *, global_param_struct *, cell_data_struct *, snow_data_struct *, soil_con_struct *, veg_var_struct *, double, double, double, double *); @@ -315,7 +315,7 @@ double trapzd( int n); void tridia(int, double *, double *, double *, double *, double *); void tridiag(double *, double *, double *, double *, unsigned int); -int vic_run(atmos_data_struct *, all_vars_struct *, dmy_struct *, +int vic_run(force_data_struct *, all_vars_struct *, dmy_struct *, global_param_struct *, lake_con_struct *, soil_con_struct *, veg_con_struct *, veg_lib_struct *); double volumetric_heat_capacity(double, double, double, double); diff --git a/vic/vic_run/src/calc_surf_energy_bal.c b/vic/vic_run/src/calc_surf_energy_bal.c index 9070d7cde..6d2e25634 100644 --- a/vic/vic_run/src/calc_surf_energy_bal.c +++ b/vic/vic_run/src/calc_surf_energy_bal.c @@ -80,7 +80,7 @@ calc_surf_energy_bal(double Le, unsigned short veg_class, double *CanopLayerBnd, double *dryFrac, - atmos_data_struct *atmos, + force_data_struct *force, dmy_struct *dmy, energy_bal_struct *energy, layer_data_struct *layer, @@ -202,11 +202,11 @@ calc_surf_energy_bal(double Le, kappa2 = energy->kappa[1]; // second layer conductivity Cs1 = energy->Cs[0]; // top layer heat capacity Cs2 = energy->Cs[1]; // second layer heat capacity - atmos_density = atmos->density[hidx]; // atmospheric density - atmos_pressure = atmos->pressure[hidx]; // atmospheric pressure - atmos_shortwave = atmos->shortwave[hidx]; // incoming shortwave radiation + atmos_density = force->density[hidx]; // atmospheric density + atmos_pressure = force->pressure[hidx]; // atmospheric pressure + atmos_shortwave = force->shortwave[hidx]; // incoming shortwave radiation if (options.CARBON) { - atmos_Catm = atmos->Catm[hidx]; // CO2 mixing ratio + atmos_Catm = force->Catm[hidx]; // CO2 mixing ratio } else { atmos_Catm = MISSING; diff --git a/vic/vic_run/src/snow_intercept.c b/vic/vic_run/src/snow_intercept.c index 39cbd54c4..083a02e63 100644 --- a/vic/vic_run/src/snow_intercept.c +++ b/vic/vic_run/src/snow_intercept.c @@ -74,7 +74,7 @@ snow_intercept(double Dt, unsigned short veg_class, double *CanopLayerBnd, double *dryFrac, - atmos_data_struct *atmos, + force_data_struct *force, layer_data_struct *layer, soil_con_struct *soil_con, veg_var_struct *veg_var) @@ -127,13 +127,13 @@ snow_intercept(double Dt, char ErrorString[MAXSTRING]; - AirDens = atmos->density[hidx]; - EactAir = atmos->vp[hidx]; - Press = atmos->pressure[hidx]; - Vpd = atmos->vpd[hidx]; - shortwave = atmos->shortwave[hidx]; + AirDens = force->density[hidx]; + EactAir = force->vp[hidx]; + Press = force->pressure[hidx]; + Vpd = force->vpd[hidx]; + shortwave = force->shortwave[hidx]; if (options.CARBON) { - Catm = atmos->Catm[hidx]; + Catm = force->Catm[hidx]; } else { Catm = MISSING; diff --git a/vic/vic_run/src/solve_snow.c b/vic/vic_run/src/solve_snow.c index 8f48fbb97..2b9d9e52f 100644 --- a/vic/vic_run/src/solve_snow.c +++ b/vic/vic_run/src/solve_snow.c @@ -83,7 +83,7 @@ solve_snow(char overstory, double *CanopLayerBnd, double *dryFrac, dmy_struct *dmy, - atmos_data_struct *atmos, + force_data_struct *force, energy_bal_struct *energy, layer_data_struct *layer, snow_data_struct *snow, @@ -114,12 +114,12 @@ solve_snow(char overstory, month = dmy->month; day_in_year = dmy->day_in_year; - density = atmos->density[hidx]; - longwave = atmos->longwave[hidx]; - pressure = atmos->pressure[hidx]; - shortwave = atmos->shortwave[hidx]; - vp = atmos->vp[hidx]; - vpd = atmos->vpd[hidx]; + density = force->density[hidx]; + longwave = force->longwave[hidx]; + pressure = force->pressure[hidx]; + shortwave = force->shortwave[hidx]; + vp = force->vp[hidx]; + vpd = force->vpd[hidx]; /* initialize moisture variables */ melt = 0.; @@ -217,7 +217,7 @@ solve_snow(char overstory, *UnderStory, band, iveg, month, hidx, veg_class, - CanopLayerBnd, dryFrac, atmos, + CanopLayerBnd, dryFrac, force, layer, soil_con, veg_var); if (ErrorFlag == ERROR) { return (ERROR); diff --git a/vic/vic_run/src/surface_fluxes.c b/vic/vic_run/src/surface_fluxes.c index 8289dcd03..de282c431 100644 --- a/vic/vic_run/src/surface_fluxes.c +++ b/vic/vic_run/src/surface_fluxes.c @@ -56,7 +56,7 @@ surface_fluxes(bool overstory, double dp, unsigned short iveg, unsigned short veg_class, - atmos_data_struct *atmos, + force_data_struct *force, dmy_struct *dmy, energy_bal_struct *energy, global_param_struct *gp, @@ -281,7 +281,7 @@ surface_fluxes(bool overstory, if frozen soils are present) ********************************/ - if (snow->swq > 0 || snow->snow_canopy > 0 || atmos->snowflag[NR]) { + if (snow->swq > 0 || snow->snow_canopy > 0 || force->snowflag[NR]) { hidx = 0; step_inc = 1; endhidx = hidx + NF; @@ -381,16 +381,16 @@ surface_fluxes(bool overstory, /* set air temperature and precipitation for this snow band */ - Tair = atmos->air_temp[hidx] + soil_con->Tfactor[band]; - step_prec = atmos->prec[hidx] * soil_con->Pfactor[band]; + Tair = force->air_temp[hidx] + soil_con->Tfactor[band]; + step_prec = force->prec[hidx] * soil_con->Pfactor[band]; // initialize ground surface temperaure Tgrnd = energy->T[0]; // initialize canopy terms Tcanopy = Tair; - VPcanopy = atmos->vp[hidx]; - VPDcanopy = atmos->vpd[hidx]; + VPcanopy = force->vp[hidx]; + VPDcanopy = force->vpd[hidx]; over_iter = 0; tol_over = 999; @@ -411,8 +411,8 @@ surface_fluxes(bool overstory, faparl(CanopLayerBnd, veg_var->LAI, soil_con->AlbedoPar, - atmos->coszen[hidx], - atmos->fdir[hidx], + force->coszen[hidx], + force->fdir[hidx], LAIlayer, faPAR); @@ -422,16 +422,16 @@ surface_fluxes(bool overstory, for (cidx = 0; cidx < options.Ncanopy; cidx++) { if (LAIlayer[cidx] > 1e-10) { veg_var->aPARLayer[cidx] = - (atmos->par[hidx] / + (force->par[hidx] / param.PHOTO_EPAR) * faPAR[cidx] / LAIlayer[cidx]; - veg_var->aPAR += atmos->par[hidx] * faPAR[cidx] / + veg_var->aPAR += force->par[hidx] * faPAR[cidx] / LAIlayer[cidx]; } else { - veg_var->aPARLayer[cidx] = atmos->par[hidx] / + veg_var->aPARLayer[cidx] = force->par[hidx] / param.PHOTO_EPAR * faPAR[cidx] / 1e-10; - veg_var->aPAR += atmos->par[hidx] * faPAR[cidx] / 1e-10; + veg_var->aPAR += force->par[hidx] * faPAR[cidx] / 1e-10; } } free((char*) LAIlayer); @@ -445,8 +445,8 @@ surface_fluxes(bool overstory, step_snow.last_snow, step_snow.surf_water, wind[2], Ls, - atmos->density[hidx], - atmos->vp[hidx], + force->density[hidx], + force->vp[hidx], roughness[2], ref_height[2], step_snow.depth, @@ -569,7 +569,7 @@ surface_fluxes(bool overstory, Nveg, iveg, band, step_dt, hidx, veg_class, &UnderStory, CanopLayerBnd, &dryFrac, - dmy, atmos, &(iter_snow_energy), + dmy, force, &(iter_snow_energy), iter_layer, &(iter_snow), soil_con, &(iter_snow_veg_var)); @@ -622,7 +622,7 @@ surface_fluxes(bool overstory, UnderStory, options.Nnode, Nveg, step_dt, hidx, iveg, (int) overstory, veg_class, - CanopLayerBnd, &dryFrac, atmos, + CanopLayerBnd, &dryFrac, force, dmy, &iter_soil_energy, iter_layer, &(iter_snow), soil_con, @@ -655,7 +655,7 @@ surface_fluxes(bool overstory, iter_snow_energy.NetShortOver, iter_soil_energy.NetShortUnder, iter_aero_resist_veg[1], Tair, - atmos->density[hidx], + force->density[hidx], &iter_soil_energy.AtmosError, &iter_soil_energy.AtmosLatent, &iter_soil_energy.AtmosLatentSub, @@ -738,10 +738,10 @@ surface_fluxes(bool overstory, vic_run_veg_lib[veg_class].CO2Specificity, iter_soil_veg_var.NscaleFactor, Tair, - atmos->shortwave[hidx], + force->shortwave[hidx], iter_soil_veg_var.aPARLayer, soil_con->elevation, - atmos->Catm[hidx], + force->Catm[hidx], CanopLayerBnd, veg_var->LAI, "rs", @@ -795,7 +795,7 @@ surface_fluxes(bool overstory, compute_pot_evap(gp->model_steps_per_day, vic_run_veg_lib[veg_class].rmin, - iter_soil_veg_var.albedo, atmos->shortwave[hidx], + iter_soil_veg_var.albedo, force->shortwave[hidx], iter_soil_energy.NetLongAtmos, vic_run_veg_lib[veg_class].RGL, Tair, VPDcanopy, iter_soil_veg_var.LAI, soil_con->elevation, diff --git a/vic/vic_run/src/vic_run.c b/vic/vic_run/src/vic_run.c index b89c82bda..98b763655 100644 --- a/vic/vic_run/src/vic_run.c +++ b/vic/vic_run/src/vic_run.c @@ -34,7 +34,7 @@ veg_lib_struct *vic_run_veg_lib; * energy and water balance models, as well as frozen soils. ******************************************************************************/ int -vic_run(atmos_data_struct *atmos, +vic_run(force_data_struct *force, all_vars_struct *all_vars, dmy_struct *dmy, global_param_struct *gp, @@ -117,17 +117,17 @@ vic_run(atmos_data_struct *atmos, /* Compute gauge undercatch correction factors - this assumes that the gauge is free of vegetation effects, so gauge correction is constant for the entire grid cell */ - if (options.CORRPREC && atmos->prec[NR] > 0) { - correct_precip(gauge_correction, atmos->wind[NR], gp->wind_h, + if (options.CORRPREC && force->prec[NR] > 0) { + correct_precip(gauge_correction, force->wind[NR], gp->wind_h, soil_con->rough, soil_con->snow_rough); } else { gauge_correction[0] = 1; gauge_correction[1] = 1; } - atmos->out_prec = 0; - atmos->out_rain = 0; - atmos->out_snow = 0; + force->out_prec = 0; + force->out_rain = 0; + force->out_snow = 0; // Convert LAI from global to local for (iveg = 0; iveg < Nveg; iveg++) { @@ -240,7 +240,7 @@ vic_run(atmos_data_struct *atmos, *************************************/ /* Initialize wind speeds */ - tmp_wind[0] = atmos->wind[NR]; + tmp_wind[0] = force->wind[NR]; tmp_wind[1] = MISSING; tmp_wind[2] = MISSING; @@ -296,7 +296,7 @@ vic_run(atmos_data_struct *atmos, vic_run_veg_lib[veg_class].NscaleFlag, veg_con[iveg].CanopLayerBnd, veg_var[iveg][band].LAI, - atmos->coszen[NR], + force->coszen[NR], veg_var[iveg][band].NscaleFactor); // TBD: move this outside of vic_run() if (dmy->day_in_year == 1) { @@ -333,7 +333,7 @@ vic_run(atmos_data_struct *atmos, &snow_inflow[band], tmp_wind, veg_con[iveg].root, options.Nlayer, Nveg, band, dp, - iveg, veg_class, atmos, dmy, + iveg, veg_class, force, dmy, &(energy[iveg][band]), gp, &(cell[iveg][band]), &(snow[iveg][band]), @@ -345,11 +345,11 @@ vic_run(atmos_data_struct *atmos, return (ERROR); } - atmos->out_prec += + force->out_prec += out_prec[band * 2] * Cv * soil_con->AreaFract[band]; - atmos->out_rain += + force->out_rain += out_rain[band * 2] * Cv * soil_con->AreaFract[band]; - atmos->out_snow += + force->out_snow += out_snow[band * 2] * Cv * soil_con->AreaFract[band]; /******************************************************** @@ -438,10 +438,10 @@ vic_run(atmos_data_struct *atmos, lake_var->baseflow_in = (sum_baseflow * lake_con->rpercent + wetland_baseflow) * soil_con->cell_area / MM_PER_M; // m3 - lake_var->channel_in = atmos->channel_in[NR] * soil_con->cell_area / + lake_var->channel_in = force->channel_in[NR] * soil_con->cell_area / MM_PER_M; // m3 - lake_var->prec = atmos->prec[NR] * lake_var->sarea / MM_PER_M; // m3 - rainonly = calc_rainonly(atmos->air_temp[NR], atmos->prec[NR], + lake_var->prec = force->prec[NR] * lake_var->sarea / MM_PER_M; // m3 + rainonly = calc_rainonly(force->air_temp[NR], force->prec[NR], param.SNOW_MAX_SNOW_TEMP, param.SNOW_MIN_RAIN_TEMP); if ((int) rainonly == ERROR) { @@ -452,19 +452,19 @@ vic_run(atmos_data_struct *atmos, Solve the energy budget for the lake. **********************************************************************/ - snowprec = gauge_correction[SNOW] * (atmos->prec[NR] - rainonly); + snowprec = gauge_correction[SNOW] * (force->prec[NR] - rainonly); rainprec = gauge_correction[SNOW] * rainonly; Cv = veg_con[iveg].Cv * lakefrac; - atmos->out_prec += (snowprec + rainprec) * Cv; - atmos->out_rain += rainprec * Cv; - atmos->out_snow += snowprec * Cv; - - ErrorFlag = solve_lake(snowprec, rainprec, atmos->air_temp[NR], - atmos->wind[NR], atmos->vp[NR] / PA_PER_KPA, - atmos->shortwave[NR], atmos->longwave[NR], - atmos->vpd[NR] / PA_PER_KPA, - atmos->pressure[NR] / PA_PER_KPA, - atmos->density[NR], lake_var, + force->out_prec += (snowprec + rainprec) * Cv; + force->out_rain += rainprec * Cv; + force->out_snow += snowprec * Cv; + + ErrorFlag = solve_lake(snowprec, rainprec, force->air_temp[NR], + force->wind[NR], force->vp[NR] / PA_PER_KPA, + force->shortwave[NR], force->longwave[NR], + force->vpd[NR] / PA_PER_KPA, + force->pressure[NR] / PA_PER_KPA, + force->density[NR], lake_var, *soil_con, gp->dt, gp->wind_h, *dmy, fraci); if (ErrorFlag == ERROR) { From 6eef1595b7b1568d67415dbd5185e416285fec42 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Wed, 6 Jul 2016 15:21:06 -0700 Subject: [PATCH 04/33] eliminate two compiler warnings, minor refactor of read_soilparam function handle --- .../classic/include/vic_driver_classic.h | 3 +- vic/drivers/classic/src/read_soilparam.c | 450 +++++++++--------- vic/drivers/classic/src/vic_classic.c | 6 +- .../include/vic_driver_shared_all.h | 2 +- vic/drivers/shared_all/src/put_data.c | 14 +- 5 files changed, 237 insertions(+), 238 deletions(-) diff --git a/vic/drivers/classic/include/vic_driver_classic.h b/vic/drivers/classic/include/vic_driver_classic.h index 0b3b74a20..634b15831 100644 --- a/vic/drivers/classic/include/vic_driver_classic.h +++ b/vic/drivers/classic/include/vic_driver_classic.h @@ -103,7 +103,8 @@ void read_initial_model_state(FILE *, all_vars_struct *, int, int, int, soil_con_struct *, lake_con_struct); lake_con_struct read_lakeparam(FILE *, soil_con_struct, veg_con_struct *); void read_snowband(FILE *, soil_con_struct *); -soil_con_struct read_soilparam(FILE *, char *, char *); +void read_soilparam(FILE *soilparam, soil_con_struct *temp, bool *RUN_MODEL, + bool *MODEL_DONE); veg_lib_struct *read_veglib(FILE *, size_t *); veg_con_struct *read_vegparam(FILE *, int, size_t); void vic_force(force_data_struct *, dmy_struct *, FILE **, veg_con_struct *, diff --git a/vic/drivers/classic/src/read_soilparam.c b/vic/drivers/classic/src/read_soilparam.c index dd9a54d2c..a71abd14c 100644 --- a/vic/drivers/classic/src/read_soilparam.c +++ b/vic/drivers/classic/src/read_soilparam.c @@ -29,10 +29,11 @@ /****************************************************************************** * @brief This routine reads soil parameters for each grid cell. *****************************************************************************/ -soil_con_struct -read_soilparam(FILE *soilparam, - char *RUN_MODEL, - char *MODEL_DONE) +void +read_soilparam(FILE *soilparam, + soil_con_struct *temp, + bool *RUN_MODEL, + bool *MODEL_DONE) { void ttrim(char *string); extern option_struct options; @@ -61,7 +62,6 @@ read_soilparam(FILE *soilparam, double zwt_prime, zwt_prime_eff; double tmp_moist; double w_avg; - soil_con_struct temp; double Zsum, dp; double tmpdp, tmpadj, Bexp; size_t k; @@ -91,7 +91,7 @@ read_soilparam(FILE *soilparam, if ((token = strtok(tmpline, delimiters)) == NULL) { log_err("Can't find values for CELL NUMBER in soil file"); } - sscanf(token, "%d", &temp.gridcel); + sscanf(token, "%d", &(temp->gridcel)); token = strtok(NULL, delimiters); while (token != NULL && (length = strlen(token)) == 0) { token = strtok(NULL, delimiters); @@ -99,7 +99,7 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for CELL LATITUDE in soil file"); } - sscanf(token, "%lf", &temp.lat); + sscanf(token, "%lf", &(temp->lat)); token = strtok(NULL, delimiters); while (token != NULL && (length = strlen(token)) == 0) { token = strtok(NULL, delimiters); @@ -107,7 +107,7 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for CELL LONGITUDE in soil file"); } - sscanf(token, "%lf", &temp.lng); + sscanf(token, "%lf", &(temp->lng)); /* read infiltration parameter */ token = strtok(NULL, delimiters); @@ -117,10 +117,10 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for INFILTRATION in soil file"); } - sscanf(token, "%lf", &temp.b_infilt); - if (temp.b_infilt <= 0) { + sscanf(token, "%lf", &(temp->b_infilt)); + if (temp->b_infilt <= 0) { log_err("b_infilt (%f) in soil file is <= 0; b_infilt must " - "be positive", temp.b_infilt); + "be positive", temp->b_infilt); } /* read fraction of baseflow rate */ @@ -132,7 +132,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for FRACTION OF BASEFLOW RATE " "in soil file"); } - sscanf(token, "%lf", &temp.Ds); + sscanf(token, "%lf", &(temp->Ds)); /* read maximum baseflow rate */ token = strtok(NULL, delimiters); @@ -143,7 +143,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for MAXIMUM BASEFLOW RATE in " "soil file"); } - sscanf(token, "%lf", &temp.Dsmax); + sscanf(token, "%lf", &(temp->Dsmax)); /* read fraction of bottom soil layer moisture */ token = strtok(NULL, delimiters); @@ -154,7 +154,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for FRACTION OF BOTTOM SOIL LAYER " "MOISTURE in soil file"); } - sscanf(token, "%lf", &temp.Ws); + sscanf(token, "%lf", &(temp->Ws)); /* read exponential */ token = strtok(NULL, delimiters); @@ -164,7 +164,7 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for EXPONENTIAL in soil file"); } - sscanf(token, "%lf", &temp.c); + sscanf(token, "%lf", &(temp->c)); /* read expt for each layer */ for (layer = 0; layer < options.Nlayer; layer++) { @@ -176,10 +176,10 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for EXPT for layer %zu in " "soil file", layer); } - sscanf(token, "%lf", &temp.expt[layer]); - if (temp.expt[layer] < 3.0) { + sscanf(token, "%lf", &(temp->expt)[layer]); + if (temp->expt[layer] < 3.0) { log_err("Exponent in layer %zu is %f < 3.0; This must be " - "> 3.0", layer, temp.expt[layer]); + "> 3.0", layer, temp->expt[layer]); } } @@ -193,7 +193,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for SATURATED HYDRAULIC " "CONDUCTIVITY for layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.Ksat[layer]); + sscanf(token, "%lf", &(temp->Ksat)[layer]); } /* read layer phi_s */ @@ -206,7 +206,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for PHI_S for layer %zu in " "soil file", layer); } - sscanf(token, "%lf", &temp.phi_s[layer]); + sscanf(token, "%lf", &(temp->phi_s)[layer]); } /* read layer initial moisture */ @@ -219,10 +219,10 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for INITIAL MOISTURE for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.init_moist[layer]); - if (temp.init_moist[layer] < 0.) { + sscanf(token, "%lf", &(temp->init_moist)[layer]); + if (temp->init_moist[layer] < 0.) { log_err("Initial moisture for layer %zu cannot be " - "negative (%f)", layer, temp.init_moist[layer]); + "negative (%f)", layer, temp->init_moist[layer]); } } @@ -235,7 +235,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for CELL MEAN ELEVATION in soil " "file"); } - sscanf(token, "%lf", &temp.elevation); + sscanf(token, "%lf", &(temp->elevation)); /* soil layer thicknesses */ for (layer = 0; layer < options.Nlayer; layer++) { @@ -247,12 +247,12 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for LAYER THICKNESS for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.depth[layer]); + sscanf(token, "%lf", &(temp->depth)[layer]); } /* round soil layer thicknesses to nearest mm */ for (layer = 0; layer < options.Nlayer; layer++) { - temp.depth[layer] = - round(temp.depth[layer] * MM_PER_M) / MM_PER_M; + temp->depth[layer] = + round(temp->depth[layer] * MM_PER_M) / MM_PER_M; } /* read average soil temperature */ @@ -264,12 +264,12 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for AVERAGE SOIL TEMPERATURE in " "soil file"); } - sscanf(token, "%lf", &temp.avg_temp); + sscanf(token, "%lf", &(temp->avg_temp)); if ((options.FULL_ENERGY || options.LAKES) && - (temp.avg_temp > 100. || temp.avg_temp < -50)) { + (temp->avg_temp > 100. || temp->avg_temp < -50)) { log_err("Need valid average soil temperature in degrees C to " "run. Full Energy model, %f is not acceptable.", - temp.avg_temp); + temp->avg_temp); } /* read soil damping depth */ @@ -281,7 +281,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for SOIL DAMPING DEPTH in soil " "file"); } - sscanf(token, "%lf", &temp.dp); + sscanf(token, "%lf", &(temp->dp)); /* read layer bubbling pressure */ for (layer = 0; layer < options.Nlayer; layer++) { @@ -293,12 +293,12 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for BUBBLING PRESSURE for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.bubble[layer]); + sscanf(token, "%lf", &(temp->bubble)[layer]); if ((options.FULL_ENERGY || - options.FROZEN_SOIL) && temp.bubble[layer] < 0) { + options.FROZEN_SOIL) && temp->bubble[layer] < 0) { log_err("Bubbling pressure in layer %zu is %f < 0; " "This must be positive for FULL_ENERGY = true or " - "FROZEN_SOIL = true", layer, temp.bubble[layer]); + "FROZEN_SOIL = true", layer, temp->bubble[layer]); } } @@ -312,12 +312,12 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for QUARTZ CONTENT for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.quartz[layer]); + sscanf(token, "%lf", &(temp->quartz)[layer]); if (options.FULL_ENERGY && - (temp.quartz[layer] > 1. || temp.quartz[layer] < 0)) { + (temp->quartz[layer] > 1. || temp->quartz[layer] < 0)) { log_err("Need valid quartz content as a fraction to run " "Full Energy model, %f is not acceptable.", - temp.quartz[layer]); + temp->quartz[layer]); } } @@ -331,10 +331,10 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for mineral BULK DENSITY " "for layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.bulk_dens_min[layer]); - if (temp.bulk_dens_min[layer] <= 0) { + sscanf(token, "%lf", &(temp->bulk_dens_min)[layer]); + if (temp->bulk_dens_min[layer] <= 0) { log_err("layer %zu mineral bulk density (%f) must " - "be > 0", layer, temp.bulk_dens_min[layer]); + "be > 0", layer, temp->bulk_dens_min[layer]); } } @@ -348,16 +348,16 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for mineral SOIL DENSITY " "for layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.soil_dens_min[layer]); - if (temp.soil_dens_min[layer] <= 0) { + sscanf(token, "%lf", &(temp->soil_dens_min)[layer]); + if (temp->soil_dens_min[layer] <= 0) { log_err("layer %zu mineral soil density (%f) must " - "be > 0", layer, temp.soil_dens_min[layer]); + "be > 0", layer, temp->soil_dens_min[layer]); } - if (temp.bulk_dens_min[layer] >= temp.soil_dens_min[layer]) { + if (temp->bulk_dens_min[layer] >= temp->soil_dens_min[layer]) { log_err("layer %zu mineral bulk density (%f) must " "be less than mineral soil density (%f)", layer, - temp.bulk_dens_min[layer], - temp.soil_dens_min[layer]); + temp->bulk_dens_min[layer], + temp->soil_dens_min[layer]); } } @@ -372,12 +372,12 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for ORGANIC CONTENT for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.organic[layer]); - if (temp.organic[layer] > 1. || temp.organic[layer] < 0) { + sscanf(token, "%lf", &(temp->organic)[layer]); + if (temp->organic[layer] > 1. || temp->organic[layer] < 0) { log_err("Need valid volumetric organic soil " "fraction when options.ORGANIC_FRACT is set " "to true. %f is not acceptable.", - temp.organic[layer]); + temp->organic[layer]); } } @@ -391,14 +391,14 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for organic BULK " "DENSITY for layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.bulk_dens_org[layer]); - if (temp.bulk_dens_org[layer] <= 0 && temp.organic[layer] > + sscanf(token, "%lf", &(temp->bulk_dens_org)[layer]); + if (temp->bulk_dens_org[layer] <= 0 && temp->organic[layer] > 0) { log_warn("layer %zu organic bulk density (%f) must " "be > 0; setting to mineral bulk density " - "(%f)", layer, temp.bulk_dens_org[layer], - temp.bulk_dens_min[layer]); - temp.bulk_dens_org[layer] = temp.bulk_dens_min[layer]; + "(%f)", layer, temp->bulk_dens_org[layer], + temp->bulk_dens_min[layer]); + temp->bulk_dens_org[layer] = temp->bulk_dens_min[layer]; } } @@ -412,29 +412,29 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for organic SOIL DENSITY for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.soil_dens_org[layer]); - if (temp.soil_dens_org[layer] <= 0 && temp.organic[layer] > + sscanf(token, "%lf", &(temp->soil_dens_org)[layer]); + if (temp->soil_dens_org[layer] <= 0 && temp->organic[layer] > 0) { log_warn("layer %zu organic soil density (%f) must be " "> 0; setting to mineral soil density (%f)", - layer, temp.soil_dens_org[layer], - temp.soil_dens_min[layer]); - temp.soil_dens_org[layer] = temp.soil_dens_min[layer]; + layer, temp->soil_dens_org[layer], + temp->soil_dens_min[layer]); + temp->soil_dens_org[layer] = temp->soil_dens_min[layer]; } - if (temp.organic[layer] > 0 && temp.bulk_dens_org[layer] >= - temp.soil_dens_org[layer]) { + if (temp->organic[layer] > 0 && temp->bulk_dens_org[layer] >= + temp->soil_dens_org[layer]) { log_err("layer %zu organic bulk density (%f) " "must be less than organic soil density (%f)", - layer, temp.bulk_dens_org[layer], - temp.soil_dens_org[layer]); + layer, temp->bulk_dens_org[layer], + temp->soil_dens_org[layer]); } } } else { for (layer = 0; layer < options.Nlayer; layer++) { - temp.organic[layer] = 0.0; - temp.bulk_dens_org[layer] = MISSING; - temp.soil_dens_org[layer] = MISSING; + temp->organic[layer] = 0.0; + temp->bulk_dens_org[layer] = MISSING; + temp->soil_dens_org[layer] = MISSING; } } @@ -482,13 +482,13 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for SOIL ROUGHNESS in soil file"); } - sscanf(token, "%lf", &temp.rough); + sscanf(token, "%lf", &(temp->rough)); /* Overwrite default bare soil aerodynamic resistance parameters with the values taken from the soil parameter file */ for (j = 0; j < MONTHS_PER_YEAR; j++) { - veg_lib[veg_lib[0].NVegLibTypes].roughness[j] = temp.rough; - veg_lib[veg_lib[0].NVegLibTypes].displacement[j] = temp.rough * + veg_lib[veg_lib[0].NVegLibTypes].roughness[j] = temp->rough; + veg_lib[veg_lib[0].NVegLibTypes].displacement[j] = temp->rough * 0.667 / 0.123; } @@ -501,7 +501,7 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for SNOW ROUGHNESS in soil file"); } - sscanf(token, "%lf", &temp.snow_rough); + sscanf(token, "%lf", &(temp->snow_rough)); /* read cell annual precipitation */ token = strtok(NULL, delimiters); @@ -511,7 +511,7 @@ read_soilparam(FILE *soilparam, if (token == NULL) { log_err("Can't find values for ANNUAL PRECIPITATION in soil file"); } - sscanf(token, "%lf", &temp.annual_prec); + sscanf(token, "%lf", &(temp->annual_prec)); /* read layer residual moisture content */ for (layer = 0; layer < options.Nlayer; layer++) { @@ -523,7 +523,7 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for RESIDUAL MOISTURE CONTENT for " "layer %zu in soil file", layer); } - sscanf(token, "%lf", &temp.resid_moist[layer]); + sscanf(token, "%lf", &(temp->resid_moist)[layer]); } /* read frozen soil active flag */ @@ -536,7 +536,7 @@ read_soilparam(FILE *soilparam, "soil file"); } sscanf(token, "%d", &tempint); - temp.FS_ACTIVE = (char)tempint; + temp->FS_ACTIVE = (char)tempint; /* read minimum snow depth for full coverage */ if (options.SPATIAL_SNOW) { @@ -548,10 +548,10 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for SPATIAL SNOW in soil file"); } sscanf(token, "%lf", &tempdbl); - temp.max_snow_distrib_slope = tempdbl; + temp->max_snow_distrib_slope = tempdbl; } else { - temp.max_snow_distrib_slope = 0; + temp->max_snow_distrib_slope = 0; } /* read slope of frozen soil distribution */ @@ -564,10 +564,10 @@ read_soilparam(FILE *soilparam, log_err("Can't find values for SPATIAL FROST in soil file"); } sscanf(token, "%lf", &tempdbl); - temp.frost_slope = tempdbl; + temp->frost_slope = tempdbl; } else { - temp.frost_slope = 0; + temp->frost_slope = 0; } /* If specified, read cell average July air temperature in the final @@ -582,7 +582,7 @@ read_soilparam(FILE *soilparam, "soil file"); } sscanf(token, "%lf", &tempdbl); - temp.avgJulyAirTemp = tempdbl; + temp->avgJulyAirTemp = tempdbl; } /******************************************* @@ -593,73 +593,73 @@ read_soilparam(FILE *soilparam, Compute Soil Layer Properties *******************************************/ for (layer = 0; layer < options.Nlayer; layer++) { - temp.bulk_density[layer] = + temp->bulk_density[layer] = (1 - - temp.organic[layer]) * temp.bulk_dens_min[layer] + - temp.organic[layer] * temp.bulk_dens_org[layer]; - temp.soil_density[layer] = + temp->organic[layer]) * temp->bulk_dens_min[layer] + + temp->organic[layer] * temp->bulk_dens_org[layer]; + temp->soil_density[layer] = (1 - - temp.organic[layer]) * temp.soil_dens_min[layer] + - temp.organic[layer] * temp.soil_dens_org[layer]; - if (temp.resid_moist[layer] == MISSING) { - temp.resid_moist[layer] = param.SOIL_RESID_MOIST; + temp->organic[layer]) * temp->soil_dens_min[layer] + + temp->organic[layer] * temp->soil_dens_org[layer]; + if (temp->resid_moist[layer] == MISSING) { + temp->resid_moist[layer] = param.SOIL_RESID_MOIST; } - temp.porosity[layer] = 1.0 - temp.bulk_density[layer] / - temp.soil_density[layer]; - temp.max_moist[layer] = temp.depth[layer] * - temp.porosity[layer] * MM_PER_M; + temp->porosity[layer] = 1.0 - temp->bulk_density[layer] / + temp->soil_density[layer]; + temp->max_moist[layer] = temp->depth[layer] * + temp->porosity[layer] * MM_PER_M; } /********************************************** Validate Soil Layer Thicknesses **********************************************/ for (layer = 0; layer < options.Nlayer; layer++) { - if (temp.depth[layer] < MINSOILDEPTH) { + if (temp->depth[layer] < MINSOILDEPTH) { log_err("Model will not function with layer %zu " - "depth %f < %f m.", layer, temp.depth[layer], + "depth %f < %f m.", layer, temp->depth[layer], MINSOILDEPTH); } } - if (temp.depth[0] > temp.depth[1]) { + if (temp->depth[0] > temp->depth[1]) { log_err("Model will not function with layer %d depth" - "(%f m) > layer %d depth (%f m).", 0, temp.depth[0], - 1, temp.depth[1]); + "(%f m) > layer %d depth (%f m).", 0, temp->depth[0], + 1, temp->depth[1]); } /********************************************** Compute Maximum Infiltration for Upper Layers **********************************************/ if (options.Nlayer == 2) { - temp.max_infil = (1.0 + temp.b_infilt) * temp.max_moist[0]; + temp->max_infil = (1.0 + temp->b_infilt) * temp->max_moist[0]; } else { - temp.max_infil = + temp->max_infil = (1.0 + - temp.b_infilt) * (temp.max_moist[0] + temp.max_moist[1]); + temp->b_infilt) * (temp->max_moist[0] + temp->max_moist[1]); } /**************************************************************** Compute Soil Layer Critical and Wilting Point Moisture Contents ****************************************************************/ for (layer = 0; layer < options.Nlayer; layer++) { - temp.Wcr[layer] = Wcr_FRACT[layer] * temp.max_moist[layer]; - temp.Wpwp[layer] = Wpwp_FRACT[layer] * temp.max_moist[layer]; - if (temp.Wpwp[layer] > temp.Wcr[layer]) { + temp->Wcr[layer] = Wcr_FRACT[layer] * temp->max_moist[layer]; + temp->Wpwp[layer] = Wpwp_FRACT[layer] * temp->max_moist[layer]; + if (temp->Wpwp[layer] > temp->Wcr[layer]) { log_err("Calculated wilting point moisture (%f mm) is " "greater than calculated critical point moisture " "(%f mm) for layer %zu.\n\tIn the soil parameter " "file, Wpwp_FRACT MUST be <= Wcr_FRACT.", - temp.Wpwp[layer], temp.Wcr[layer], layer); + temp->Wpwp[layer], temp->Wcr[layer], layer); } - if (temp.Wpwp[layer] < temp.resid_moist[layer] * - temp.depth[layer] * MM_PER_M) { + if (temp->Wpwp[layer] < temp->resid_moist[layer] * + temp->depth[layer] * MM_PER_M) { log_err("Calculated wilting point moisture (%f mm) is " "less than calculated residual moisture (%f mm) " "for layer %zu.\n\tIn the soil parameter file, " "Wpwp_FRACT MUST be >= resid_moist / (1.0 - " "bulk_density/soil_density).", - temp.Wpwp[layer], temp.resid_moist[layer] * - temp.depth[layer] * MM_PER_M, layer); + temp->Wpwp[layer], temp->resid_moist[layer] * + temp->depth[layer] * MM_PER_M, layer); } } @@ -667,29 +667,29 @@ read_soilparam(FILE *soilparam, Validate Spatial Snow/Frost Params **********************************************/ if (options.SPATIAL_SNOW) { - if (temp.max_snow_distrib_slope < 0.0) { + if (temp->max_snow_distrib_slope < 0.0) { log_err("max_snow_distrib_slope (%f) must be positive.", - temp.max_snow_distrib_slope); + temp->max_snow_distrib_slope); } } if (options.SPATIAL_FROST) { - if (temp.frost_slope < 0.0) { + if (temp->frost_slope < 0.0) { log_err("frost_slope (%f) must be positive.", - temp.frost_slope); + temp->frost_slope); } } for (k = 0; k < options.Nfrost; k++) { if (options.Nfrost == 1) { - temp.frost_fract[k] = 1.; + temp->frost_fract[k] = 1.; } else if (options.Nfrost == 2) { - temp.frost_fract[k] = 0.5; + temp->frost_fract[k] = 0.5; } else { - temp.frost_fract[k] = 1. / (options.Nfrost - 1); + temp->frost_fract[k] = 1. / (options.Nfrost - 1); if (k == 0 || k == options.Nfrost - 1) { - temp.frost_fract[k] /= 2.; + temp->frost_fract[k] /= 2.; } } } @@ -701,28 +701,28 @@ read_soilparam(FILE *soilparam, *************************************************/ if (options.BASEFLOW == NIJSSEN2001) { layer = options.Nlayer - 1; - temp.Dsmax = temp.Dsmax * - pow( - (double) (1. / (temp.max_moist[layer] - temp.Ws)), - -temp.c) + - temp.Ds * temp.max_moist[layer]; - temp.Ds = temp.Ds * temp.Ws / temp.Dsmax; - temp.Ws = temp.Ws / temp.max_moist[layer]; + temp->Dsmax = temp->Dsmax * + pow( + (double) (1. / (temp->max_moist[layer] - temp->Ws)), + -temp->c) + + temp->Ds * temp->max_moist[layer]; + temp->Ds = temp->Ds * temp->Ws / temp->Dsmax; + temp->Ws = temp->Ws / temp->max_moist[layer]; } // Soil thermal node thicknesses and positions Nnodes = options.Nnode; - dp = temp.dp; + dp = temp->dp; if (options.QUICK_FLUX) { /* node thicknesses */ - temp.dz_node[0] = temp.depth[0]; - temp.dz_node[1] = temp.depth[0]; - temp.dz_node[2] = 2. * (dp - 1.5 * temp.depth[0]); + temp->dz_node[0] = temp->depth[0]; + temp->dz_node[1] = temp->depth[0]; + temp->dz_node[2] = 2. * (dp - 1.5 * temp->depth[0]); /* node depths (positions) */ - temp.Zsum_node[0] = 0; - temp.Zsum_node[1] = temp.depth[0]; - temp.Zsum_node[2] = dp; + temp->Zsum_node[0] = 0; + temp->Zsum_node[1] = temp->depth[0]; + temp->Zsum_node[2] = dp; } else { if (!options.EXP_TRANS) { @@ -733,26 +733,28 @@ read_soilparam(FILE *soilparam, between the damping depth and twice the depth of the first layer. */ - temp.dz_node[0] = temp.depth[0]; - temp.dz_node[1] = temp.depth[0]; - temp.dz_node[2] = temp.depth[0]; - temp.Zsum_node[0] = 0; - temp.Zsum_node[1] = temp.depth[0]; - Zsum = 2. * temp.depth[0]; - temp.Zsum_node[2] = Zsum; - tmpdp = dp - temp.depth[0] * 2.5; + temp->dz_node[0] = temp->depth[0]; + temp->dz_node[1] = temp->depth[0]; + temp->dz_node[2] = temp->depth[0]; + temp->Zsum_node[0] = 0; + temp->Zsum_node[1] = temp->depth[0]; + Zsum = 2. * temp->depth[0]; + temp->Zsum_node[2] = Zsum; + tmpdp = dp - temp->depth[0] * 2.5; tmpadj = 3.5; for (k = 3; k < Nnodes - 1; k++) { - temp.dz_node[k] = tmpdp / (((double) Nnodes - tmpadj)); - Zsum += (temp.dz_node[k] + temp.dz_node[k - 1]) / 2.; - temp.Zsum_node[k] = Zsum; + temp->dz_node[k] = tmpdp / (((double) Nnodes - tmpadj)); + Zsum += (temp->dz_node[k] + temp->dz_node[k - 1]) / 2.; + temp->Zsum_node[k] = Zsum; } - temp.dz_node[Nnodes - - 1] = (dp - Zsum - temp.dz_node[Nnodes - 2] / 2.) * - 2.; - Zsum += (temp.dz_node[Nnodes - 2] + temp.dz_node[Nnodes - 1]) / - 2.; - temp.Zsum_node[Nnodes - 1] = Zsum; + temp->dz_node[Nnodes - + 1] = + (dp - Zsum - temp->dz_node[Nnodes - 2] / 2.) * + 2.; + Zsum += + (temp->dz_node[Nnodes - 2] + temp->dz_node[Nnodes - 1]) / + 2.; + temp->Zsum_node[Nnodes - 1] = Zsum; if ((int) (Zsum * MM_PER_M + 0.5) != (int) (dp * MM_PER_M + 0.5)) { log_err("Sum of thermal node thicknesses (%f) " @@ -786,60 +788,60 @@ read_soilparam(FILE *soilparam, exp(0.2 * (Nnodes - 1)) + 1); } for (k = 0; k <= Nnodes - 1; k++) { - temp.Zsum_node[k] = expf(Bexp * k) - 1.; + temp->Zsum_node[k] = expf(Bexp * k) - 1.; } - if (temp.Zsum_node[0] > temp.depth[0]) { + if (temp->Zsum_node[0] > temp->depth[0]) { log_err("Depth of first thermal node (%f) in " "initialize_model_state is greater " "than depth of first soil layer (%f); " "increase the number of nodes or " "decrease the thermal damping depth " - "dp (%f)", temp.Zsum_node[0], temp.depth[0], dp); + "dp (%f)", temp->Zsum_node[0], temp->depth[0], dp); } // top node k = 0; - temp.dz_node[k] = temp.Zsum_node[k + 1] - temp.Zsum_node[k]; + temp->dz_node[k] = temp->Zsum_node[k + 1] - temp->Zsum_node[k]; // middle nodes for (k = 1; k < Nnodes - 1; k++) { - temp.dz_node[k] = - (temp.Zsum_node[k + 1] - temp.Zsum_node[k]) / 2. + - (temp.Zsum_node[k] - temp.Zsum_node[k - 1]) / 2.; + temp->dz_node[k] = + (temp->Zsum_node[k + 1] - temp->Zsum_node[k]) / 2. + + (temp->Zsum_node[k] - temp->Zsum_node[k - 1]) / 2.; } // bottom node k = Nnodes - 1; - temp.dz_node[k] = temp.Zsum_node[k] - temp.Zsum_node[k - 1]; + temp->dz_node[k] = temp->Zsum_node[k] - temp->Zsum_node[k - 1]; } // end if !EXP_TRANS } /******************************************************************* Calculate grid cell area. ******************************************************************/ - compute_cell_area(&temp); + compute_cell_area(temp); /************************************************* Allocate and Initialize Snow Band Parameters *************************************************/ Nbands = options.SNOW_BAND; - temp.AreaFract = calloc(Nbands, sizeof(*(temp.AreaFract))); - check_alloc_status(temp.AreaFract, "Memory allocation error."); - temp.BandElev = calloc(Nbands, sizeof(*(temp.BandElev))); - check_alloc_status(temp.BandElev, "Memory allocation error."); - temp.Tfactor = calloc(Nbands, sizeof(*(temp.Tfactor))); - check_alloc_status(temp.Tfactor, "Memory allocation error."); - temp.Pfactor = calloc(Nbands, sizeof(*(temp.Pfactor))); - check_alloc_status(temp.Pfactor, "Memory allocation error."); - temp.AboveTreeLine = calloc(Nbands, sizeof(*(temp.AboveTreeLine))); - check_alloc_status(temp.AboveTreeLine, "Memory allocation error."); + temp->AreaFract = calloc(Nbands, sizeof(*(temp->AreaFract))); + check_alloc_status(temp->AreaFract, "Memory allocation error."); + temp->BandElev = calloc(Nbands, sizeof(*(temp->BandElev))); + check_alloc_status(temp->BandElev, "Memory allocation error."); + temp->Tfactor = calloc(Nbands, sizeof(*(temp->Tfactor))); + check_alloc_status(temp->Tfactor, "Memory allocation error."); + temp->Pfactor = calloc(Nbands, sizeof(*(temp->Pfactor))); + check_alloc_status(temp->Pfactor, "Memory allocation error."); + temp->AboveTreeLine = calloc(Nbands, sizeof(*(temp->AboveTreeLine))); + check_alloc_status(temp->AboveTreeLine, "Memory allocation error."); /** Set default values for factors to use unmodified forcing data **/ for (band = 0; band < Nbands; band++) { - temp.AreaFract[band] = 0.; - temp.BandElev[band] = temp.elevation; - temp.Tfactor[band] = 0.; - temp.Pfactor[band] = 1.; + temp->AreaFract[band] = 0.; + temp->BandElev[band] = temp->elevation; + temp->Tfactor[band] = 0.; + temp->Pfactor[band] = 1.; } - temp.AreaFract[0] = 1.; + temp->AreaFract[0] = 1.; /************************************************* Compute soil moistures for various values of water table depth @@ -882,36 +884,36 @@ read_soilparam(FILE *soilparam, /* Individual layers */ tmp_depth = 0; for (layer = 0; layer < options.Nlayer; layer++) { - b = 0.5 * (temp.expt[layer] - 3); - bubble = temp.bubble[layer]; - tmp_resid_moist = temp.resid_moist[layer] * temp.depth[layer] * + b = 0.5 * (temp->expt[layer] - 3); + bubble = temp->bubble[layer]; + tmp_resid_moist = temp->resid_moist[layer] * temp->depth[layer] * MM_PER_M; // in mm zwt_prime = 0; // depth of free water surface below top of layer (not yet elevation) for (i = 0; i < MAX_ZWTVMOIST; i++) { - temp.zwtvmoist_zwt[layer][i] = -tmp_depth * CM_PER_M - - zwt_prime; // elevation (cm) relative to soil surface - w_avg = (temp.depth[layer] * CM_PER_M - zwt_prime - + temp->zwtvmoist_zwt[layer][i] = -tmp_depth * CM_PER_M - + zwt_prime; // elevation (cm) relative to soil surface + w_avg = (temp->depth[layer] * CM_PER_M - zwt_prime - (b / (b - 1)) * bubble * (1 - pow((zwt_prime + bubble) / bubble, (b - 1) / b))) / - (temp.depth[layer] * CM_PER_M); // in cm + (temp->depth[layer] * CM_PER_M); // in cm if (w_avg < 0) { w_avg = 0; } if (w_avg > 1) { w_avg = 1; } - temp.zwtvmoist_moist[layer][i] = w_avg * - (temp.max_moist[layer] - - tmp_resid_moist) + - tmp_resid_moist; - zwt_prime += temp.depth[layer] * CM_PER_M / + temp->zwtvmoist_moist[layer][i] = w_avg * + (temp->max_moist[layer] - + tmp_resid_moist) + + tmp_resid_moist; + zwt_prime += temp->depth[layer] * CM_PER_M / (MAX_ZWTVMOIST - 1); // in cm } - tmp_depth += temp.depth[layer]; + tmp_depth += temp->depth[layer]; } /* Top N-1 layers lumped together (with average soil properties) */ @@ -921,18 +923,18 @@ read_soilparam(FILE *soilparam, tmp_max_moist = 0; tmp_resid_moist = 0; for (layer = 0; layer < options.Nlayer - 1; layer++) { - b += 0.5 * (temp.expt[layer] - 3) * temp.depth[layer]; - bubble += temp.bubble[layer] * temp.depth[layer]; - tmp_max_moist += temp.max_moist[layer]; // total max_moist - tmp_resid_moist += temp.resid_moist[layer] * temp.depth[layer] * + b += 0.5 * (temp->expt[layer] - 3) * temp->depth[layer]; + bubble += temp->bubble[layer] * temp->depth[layer]; + tmp_max_moist += temp->max_moist[layer]; // total max_moist + tmp_resid_moist += temp->resid_moist[layer] * temp->depth[layer] * MM_PER_M; // total resid_moist in mm - tmp_depth += temp.depth[layer]; + tmp_depth += temp->depth[layer]; } b /= tmp_depth; // average b bubble /= tmp_depth; // average bubble zwt_prime = 0; // depth of free water surface below top of layer (not yet elevation) for (i = 0; i < MAX_ZWTVMOIST; i++) { - temp.zwtvmoist_zwt[options.Nlayer][i] = -zwt_prime; // elevation (cm) relative to soil surface + temp->zwtvmoist_zwt[options.Nlayer][i] = -zwt_prime; // elevation (cm) relative to soil surface w_avg = (tmp_depth * CM_PER_M - zwt_prime - (b / (b - @@ -946,45 +948,45 @@ read_soilparam(FILE *soilparam, if (w_avg > 1) { w_avg = 1; } - temp.zwtvmoist_moist[options.Nlayer][i] = w_avg * - (tmp_max_moist - - tmp_resid_moist) + - tmp_resid_moist; + temp->zwtvmoist_moist[options.Nlayer][i] = w_avg * + (tmp_max_moist - + tmp_resid_moist) + + tmp_resid_moist; zwt_prime += tmp_depth * CM_PER_M / (MAX_ZWTVMOIST - 1); // in cm } /* Compute zwt by taking total column soil moisture and filling column from bottom up */ tmp_depth = 0; for (layer = 0; layer < options.Nlayer; layer++) { - tmp_depth += temp.depth[layer]; + tmp_depth += temp->depth[layer]; } zwt_prime = 0; // depth of free water surface below soil surface (not yet elevation) for (i = 0; i < MAX_ZWTVMOIST; i++) { - temp.zwtvmoist_zwt[options.Nlayer + 1][i] = -zwt_prime; // elevation (cm) relative to soil surface + temp->zwtvmoist_zwt[options.Nlayer + 1][i] = -zwt_prime; // elevation (cm) relative to soil surface // Integrate w_avg in pieces if (zwt_prime == 0) { tmp_moist = 0; for (layer = 0; layer < options.Nlayer; layer++) { - tmp_moist += temp.max_moist[layer]; + tmp_moist += temp->max_moist[layer]; } - temp.zwtvmoist_moist[options.Nlayer + 1][i] = tmp_moist; + temp->zwtvmoist_moist[options.Nlayer + 1][i] = tmp_moist; } else { tmp_moist = 0; layer = options.Nlayer - 1; - tmp_depth2 = tmp_depth - temp.depth[layer]; + tmp_depth2 = tmp_depth - temp->depth[layer]; while (layer > 0 && zwt_prime <= tmp_depth2 * CM_PER_M) { - tmp_moist += temp.max_moist[layer]; + tmp_moist += temp->max_moist[layer]; layer--; - tmp_depth2 -= temp.depth[layer]; + tmp_depth2 -= temp->depth[layer]; } w_avg = - (tmp_depth2 * CM_PER_M + temp.depth[layer] * CM_PER_M - - zwt_prime) / (temp.depth[layer] * CM_PER_M); - b = 0.5 * (temp.expt[layer] - 3); - bubble = temp.bubble[layer]; - tmp_resid_moist = temp.resid_moist[layer] * - temp.depth[layer] * MM_PER_M; + (tmp_depth2 * CM_PER_M + temp->depth[layer] * CM_PER_M - + zwt_prime) / (temp->depth[layer] * CM_PER_M); + b = 0.5 * (temp->expt[layer] - 3); + bubble = temp->bubble[layer]; + tmp_resid_moist = temp->resid_moist[layer] * + temp->depth[layer] * MM_PER_M; w_avg += -(b / (b - @@ -992,20 +994,20 @@ read_soilparam(FILE *soilparam, (1 - pow((zwt_prime + bubble - tmp_depth2 * CM_PER_M) / bubble, - (b - 1) / b)) / (temp.depth[layer] * CM_PER_M); + (b - 1) / b)) / (temp->depth[layer] * CM_PER_M); tmp_moist += w_avg * - (temp.max_moist[layer] - + (temp->max_moist[layer] - tmp_resid_moist) + tmp_resid_moist; b_save = b; bub_save = bubble; tmp_depth2_save = tmp_depth2; while (layer > 0) { layer--; - tmp_depth2 -= temp.depth[layer]; - b = 0.5 * (temp.expt[layer] - 3); - bubble = temp.bubble[layer]; - tmp_resid_moist = temp.resid_moist[layer] * - temp.depth[layer] * MM_PER_M; + tmp_depth2 -= temp->depth[layer]; + b = 0.5 * (temp->expt[layer] - 3); + bubble = temp->bubble[layer]; + tmp_resid_moist = temp->resid_moist[layer] * + temp->depth[layer] * MM_PER_M; zwt_prime_eff = tmp_depth2_save * CM_PER_M - bubble + bubble * pow( @@ -1018,24 +1020,24 @@ read_soilparam(FILE *soilparam, (1 - pow((zwt_prime_eff + bubble - tmp_depth2 * CM_PER_M) / bubble, - (b - 1) / b)) / (temp.depth[layer] * CM_PER_M); + (b - 1) / b)) / (temp->depth[layer] * CM_PER_M); tmp_moist += w_avg * - (temp.max_moist[layer] - + (temp->max_moist[layer] - tmp_resid_moist) + tmp_resid_moist; b_save = b; bub_save = bubble; tmp_depth2_save = tmp_depth2; } - temp.zwtvmoist_moist[options.Nlayer + 1][i] = tmp_moist; + temp->zwtvmoist_moist[options.Nlayer + 1][i] = tmp_moist; } zwt_prime += tmp_depth * CM_PER_M / (MAX_ZWTVMOIST - 1); // in cm } /* Compute soil albedo in PAR range (400-700nm) following eqn 122 in Knorr 1997 */ if (options.CARBON) { - temp.AlbedoPar = 0.92 * param.ALBEDO_BARE_SOIL - 0.015; - if (temp.AlbedoPar < param.PHOTO_ALBSOIPARMIN) { - temp.AlbedoPar = param.PHOTO_ALBSOIPARMIN; + temp->AlbedoPar = 0.92 * param.ALBEDO_BARE_SOIL - 0.015; + if (temp->AlbedoPar < param.PHOTO_ALBSOIPARMIN) { + temp->AlbedoPar = param.PHOTO_ALBSOIPARMIN; } } @@ -1043,13 +1045,11 @@ read_soilparam(FILE *soilparam, Miscellaneous terms for MTCLIM disaggregation *************************************************/ /* Central Longitude of Current Time Zone */ - temp.time_zone_lng = off_gmt * 360. / HOURS_PER_DAY; + temp->time_zone_lng = off_gmt * 360. / HOURS_PER_DAY; /* Assume flat grid cell for radiation calculations */ - temp.slope = 0; - temp.aspect = 0; - temp.whoriz = 0; - temp.ehoriz = 0; + temp->slope = 0; + temp->aspect = 0; + temp->whoriz = 0; + temp->ehoriz = 0; } // end if(!(*MODEL_DONE) && (*RUN_MODEL)) - - return temp; } diff --git a/vic/drivers/classic/src/vic_classic.c b/vic/drivers/classic/src/vic_classic.c index 09a7d4bf8..ef6a65ce3 100644 --- a/vic/drivers/classic/src/vic_classic.c +++ b/vic/drivers/classic/src/vic_classic.c @@ -58,8 +58,8 @@ main(int argc, /** Variable Declarations **/ extern FILE *LOG_DEST; - char MODEL_DONE; - char RUN_MODEL; + bool MODEL_DONE; + bool RUN_MODEL; char dmy_str[MAXSTRING]; size_t rec; size_t Nveg_type; @@ -156,7 +156,7 @@ main(int argc, ************************************/ MODEL_DONE = false; while (!MODEL_DONE) { - soil_con = read_soilparam(filep.soilparam, &RUN_MODEL, &MODEL_DONE); + read_soilparam(filep.soilparam, &soil_con, &RUN_MODEL, &MODEL_DONE); if (RUN_MODEL) { cellnum++; diff --git a/vic/drivers/shared_all/include/vic_driver_shared_all.h b/vic/drivers/shared_all/include/vic_driver_shared_all.h index f220d6000..e832b88cc 100644 --- a/vic/drivers/shared_all/include/vic_driver_shared_all.h +++ b/vic/drivers/shared_all/include/vic_driver_shared_all.h @@ -566,7 +566,7 @@ void collect_eb_terms(energy_bal_struct, snow_data_struct, cell_data_struct, double *, double, double **); void collect_wb_terms(cell_data_struct, veg_var_struct, snow_data_struct, double, double, double, bool, double, bool, double *, - double *, double **); + double **); void compute_derived_state_vars(all_vars_struct *, soil_con_struct *, veg_con_struct *); void compute_lake_params(lake_con_struct *, soil_con_struct); diff --git a/vic/drivers/shared_all/src/put_data.c b/vic/drivers/shared_all/src/put_data.c index 3e63780bd..12c6f441f 100644 --- a/vic/drivers/shared_all/src/put_data.c +++ b/vic/drivers/shared_all/src/put_data.c @@ -228,7 +228,6 @@ put_data(all_vars_struct *all_vars, HasVeg, (1 - Clake), overstory, - depth, frost_fract, out_data); @@ -298,7 +297,6 @@ put_data(all_vars_struct *all_vars, 0, Clake, overstory, - depth, frost_fract, out_data); @@ -491,10 +489,12 @@ put_data(all_vars_struct *all_vars, out_data[OUT_SMLIQFRAC][index] = out_data[OUT_SOIL_LIQ][index] / out_data[OUT_SOIL_MOIST][index]; out_data[OUT_SMFROZFRAC][index] = 1 - out_data[OUT_SMLIQFRAC][index]; - out_data[OUT_SOIL_LIQ_FRAC][index] = out_data[OUT_SOIL_LIQ][index] / (depth[index] * - MM_PER_M); - out_data[OUT_SOIL_ICE_FRAC][index] = out_data[OUT_SOIL_ICE][index] / (depth[index] * - MM_PER_M); + out_data[OUT_SOIL_LIQ_FRAC][index] = out_data[OUT_SOIL_LIQ][index] / + (depth[index] * + MM_PER_M); + out_data[OUT_SOIL_ICE_FRAC][index] = out_data[OUT_SOIL_ICE][index] / + (depth[index] * + MM_PER_M); } out_data[OUT_DELSOILMOIST][0] -= save_data->total_soil_moist; out_data[OUT_DELSWE][0] = out_data[OUT_SWE][0] + @@ -582,7 +582,6 @@ collect_wb_terms(cell_data_struct cell, bool HasVeg, double lakefactor, bool overstory, - double *depth, double *frost_fract, double **out_data) { @@ -696,7 +695,6 @@ collect_wb_terms(cell_data_struct cell, out_data[OUT_SOIL_LIQ][index] += tmp_moist * AreaFactor; out_data[OUT_SOIL_ICE][index] += tmp_ice * AreaFactor; - } out_data[OUT_SOIL_WET][0] += cell.wetness * AreaFactor; out_data[OUT_ROOTMOIST][0] += cell.rootmoist * AreaFactor; From c67266a93c9a3d7a4747707b9cfa911ee0e2f8fb Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Wed, 6 Jul 2016 16:01:05 -0700 Subject: [PATCH 05/33] enable multiple output files (in time) per history stream --- vic/drivers/shared_image/src/vic_init_output.c | 11 +++-------- vic/drivers/shared_image/src/vic_write.c | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/vic/drivers/shared_image/src/vic_init_output.c b/vic/drivers/shared_image/src/vic_init_output.c index 97bc7e7d5..45037e22c 100644 --- a/vic/drivers/shared_image/src/vic_init_output.c +++ b/vic/drivers/shared_image/src/vic_init_output.c @@ -186,20 +186,13 @@ vic_init_output(dmy_struct *dmy_current) output_streams[streamnum].nvars, output_streams[streamnum].varid, output_streams[streamnum].type); - - if (mpi_rank == VIC_MPI_ROOT) { - // open the netcdf history file - initialize_history_file(&(nc_hist_files[streamnum]), - &(output_streams[streamnum]), - dmy_current); - } } // validate streams validate_streams(&output_streams); } /****************************************************************************** - * @brief Initialize history files + * @brief Initialize history file *****************************************************************************/ void initialize_history_file(nc_file_struct *nc, @@ -646,6 +639,8 @@ initialize_nc_file(nc_file_struct *nc_file, size_t i; + nc_file->open = false; + // Set fill values nc_file->c_fillvalue = NC_FILL_CHAR; nc_file->s_fillvalue = NC_FILL_SHORT; diff --git a/vic/drivers/shared_image/src/vic_write.c b/vic/drivers/shared_image/src/vic_write.c index b5f7860da..af7620037 100644 --- a/vic/drivers/shared_image/src/vic_write.c +++ b/vic/drivers/shared_image/src/vic_write.c @@ -78,6 +78,13 @@ vic_write(stream_struct *stream, unsigned int varid; int status; + if (mpi_rank == VIC_MPI_ROOT) { + // If the output file is not open, initialize the history file now. + if (nc_hist_file->open == false) { + // open the netcdf history file + initialize_history_file(nc_hist_file, stream, dmy_current); + } + } // initialize dimids to invalid values - helps debugging for (i = 0; i < MAXDIMS; i++) { @@ -216,7 +223,15 @@ vic_write(stream_struct *stream, // Advance the position in the history file stream->write_alarm.count++; - // TODO: Decide if it is time to close this file and open a new one. + if (raise_alarm(&(stream->write_alarm), dmy_current)) { + // close this history file + if (mpi_rank == VIC_MPI_ROOT) { + status = nc_close(nc_hist_file->nc_id); + check_nc_status(status, "Error closing history file"); + nc_hist_file->open = false; + } + reset_alarm(&(stream->write_alarm), dmy_current); + } // free memory if (dvar != NULL) { From 3fd8bfd1b90ba80df15b0a41b267cee31d4666fe Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 7 Jul 2016 13:10:41 -0700 Subject: [PATCH 06/33] Check that the domain information in the parameters file matches the global domain info (#555) * check that the domain information in the image driver parameters file matches the global domain (file) --- vic/drivers/shared_all/src/open_file.c | 2 +- .../include/vic_driver_shared_image.h | 4 +- .../shared_image/src/check_domain_info.c | 84 +++++++++++++++++++ .../shared_image/src/get_global_domain.c | 33 ++++---- vic/drivers/shared_image/src/vic_init.c | 5 -- vic/drivers/shared_image/src/vic_start.c | 5 +- 6 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 vic/drivers/shared_image/src/check_domain_info.c diff --git a/vic/drivers/shared_all/src/open_file.c b/vic/drivers/shared_all/src/open_file.c index 59004f0d1..0144bd83e 100644 --- a/vic/drivers/shared_all/src/open_file.c +++ b/vic/drivers/shared_all/src/open_file.c @@ -33,7 +33,7 @@ * @type Type has one of the associated values with it: * - "r" open for reading * - "w" truncate or create for writing - * - "a" append; open for writing at end of file, or create for + * - "a" append; open for writing at end of file, or create for * writing * - "r+" open for update (reading and writing) * - "w+" truncate or create for update diff --git a/vic/drivers/shared_image/include/vic_driver_shared_image.h b/vic/drivers/shared_image/include/vic_driver_shared_image.h index 596e0ed0c..dc0d92543 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -190,10 +190,12 @@ void alloc_veg_hist(veg_hist_struct *veg_hist); double air_density(double t, double p); double average(double *ar, size_t n); void check_init_state_file(void); +void compare_ncdomain_with_global_domain(char *ncfile); void free_force(force_data_struct *force); void free_veg_hist(veg_hist_struct *veg_hist); void get_domain_type(char *cmdstr); -size_t get_global_domain(char *fname, domain_struct *global_domain); +size_t get_global_domain(char *fname, domain_struct *global_domain, + bool coords_only); size_t get_nc_dimension(char *nc_name, char *dim_name); void get_nc_var_attr(char *nc_name, char *var_name, char *attr_name, char **attr); diff --git a/vic/drivers/shared_image/src/check_domain_info.c b/vic/drivers/shared_image/src/check_domain_info.c new file mode 100644 index 000000000..32d6aa61a --- /dev/null +++ b/vic/drivers/shared_image/src/check_domain_info.c @@ -0,0 +1,84 @@ +/****************************************************************************** + * @section DESCRIPTION + * + * Routines to compare the global domain to the other VIC input files, such as + * parameter or state files. + * + * @section LICENSE + * + * The Variable Infiltration Capacity (VIC) macroscale hydrological model + * Copyright (C) 2016 The Computational Hydrology Group, Department of Civil + * and Environmental Engineering, University of Washington. + * + * The VIC model is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *****************************************************************************/ + + #include + +/****************************************************************************** + * @brief Check that the cooridnates, dimensions, and mask variables in a + netcdf file matches the global domain. + *****************************************************************************/ +void +compare_ncdomain_with_global_domain(char *ncfile) +{ + extern domain_struct global_domain; + + domain_struct ncfile_domain; + + size_t i; + + ncfile_domain.info = global_domain.info; + + // read the domain info from ncfile (e.g. parameters file or state file) + get_global_domain(ncfile, &ncfile_domain, true); + + // using the ncfile_domain, we can compare the values to the global domain. + + // dimension shapes match (lat/lon) + if (global_domain.n_nx != ncfile_domain.n_nx) { + log_err("x dimension in parameters file does not match domain"); + } + if (global_domain.n_ny != ncfile_domain.n_ny) { + log_err("y dimension in parameters file does not match domain"); + } + + // loop over all grid cells and check that the two domains are identical + for (i = 0; i < global_domain.ncells_total; i++) { + // mask matches + if (ncfile_domain.locations[i].run > global_domain.locations[i].run) { + log_err("parameter file mask for gridcell %zu is zero and the " + "domain file specifies that this cell should be run", i); + } + // latitude matches + if (!assert_close_double(ncfile_domain.locations[i].latitude, + global_domain.locations[i].latitude, + 0, 0.01)) { + log_err("latitude in parameter (%lf) file does not match the " + "latitude in the domain file (%lf) for gridcell %zu", + ncfile_domain.locations[i].latitude, + global_domain.locations[i].latitude, i); + } + // longitude matches + if (!assert_close_double(ncfile_domain.locations[i].longitude, + global_domain.locations[i].longitude, + 0, 0.01)) { + log_err("longitude in parameter (%lf) file does not match the " + "longitude in the domain file (%lf) for gridcell %zu", + ncfile_domain.locations[i].longitude, + global_domain.locations[i].longitude, i); + } + } +} diff --git a/vic/drivers/shared_image/src/get_global_domain.c b/vic/drivers/shared_image/src/get_global_domain.c index 375145860..6dbdd0574 100644 --- a/vic/drivers/shared_image/src/get_global_domain.c +++ b/vic/drivers/shared_image/src/get_global_domain.c @@ -31,7 +31,8 @@ *****************************************************************************/ size_t get_global_domain(char *nc_name, - domain_struct *global_domain) + domain_struct *global_domain, + bool coords_only) { int *run = NULL; double *var = NULL; @@ -70,7 +71,6 @@ get_global_domain(char *nc_name, debug("%zu active grid cells found in domain mask", global_domain->ncells_active); - // if MASTER_PROC global_domain->locations = malloc(global_domain->ncells_total * sizeof(*global_domain->locations)); check_alloc_status(global_domain->locations, "Memory allocation error."); @@ -175,22 +175,25 @@ get_global_domain(char *nc_name, nc_name); } - // get area - // TBD: read var id from file - get_nc_field_double(nc_name, global_domain->info.area_var, - d2start, d2count, var); - for (i = 0; i < global_domain->ncells_total; i++) { - global_domain->locations[i].area = var[i]; - } + if (!coords_only) { + // get area + // TBD: read var id from file + get_nc_field_double(nc_name, global_domain->info.area_var, + d2start, d2count, var); + for (i = 0; i < global_domain->ncells_total; i++) { + global_domain->locations[i].area = var[i]; + } - // get fraction - // TBD: read var id from file - get_nc_field_double(nc_name, global_domain->info.frac_var, - d2start, d2count, var); - for (i = 0; i < global_domain->ncells_total; i++) { - global_domain->locations[i].frac = var[i]; + // get fraction + // TBD: read var id from file + get_nc_field_double(nc_name, global_domain->info.frac_var, + d2start, d2count, var); + for (i = 0; i < global_domain->ncells_total; i++) { + global_domain->locations[i].frac = var[i]; + } } + // free memory free(var); free(run); diff --git a/vic/drivers/shared_image/src/vic_init.c b/vic/drivers/shared_image/src/vic_init.c index 353453cc8..0b00483eb 100644 --- a/vic/drivers/shared_image/src/vic_init.c +++ b/vic/drivers/shared_image/src/vic_init.c @@ -74,14 +74,12 @@ vic_init(void) Cv_sum = malloc(local_domain.ncells_active * sizeof(*Cv_sum)); check_alloc_status(Cv_sum, "Memory allocation error."); - // allocate memory for variables to be read dvar = malloc(local_domain.ncells_active * sizeof(*dvar)); check_alloc_status(dvar, "Memory allocation error."); ivar = malloc(local_domain.ncells_active * sizeof(*ivar)); check_alloc_status(ivar, "Memory allocation error."); - // The method used to convert the NetCDF fields to VIC structures for // individual grid cells is to read a 2D slice and then loop over the // domain cells to assign the values to the VIC structures @@ -405,9 +403,6 @@ vic_init(void) // read_soilparam() - // Nlayer - options.Nlayer = get_nc_dimension(filenames.params, "nlayer"); - // Validate Nlayer if ((options.FULL_ENERGY || options.FROZEN_SOIL) && options.Nlayer < 3) { diff --git a/vic/drivers/shared_image/src/vic_start.c b/vic/drivers/shared_image/src/vic_start.c index ace88c4e4..7090b515b 100644 --- a/vic/drivers/shared_image/src/vic_start.c +++ b/vic/drivers/shared_image/src/vic_start.c @@ -74,7 +74,7 @@ vic_start(void) } // read domain info - get_global_domain(filenames.domain, &global_domain); + get_global_domain(filenames.domain, &global_domain, false); // add the number of vegetation type to the location info in the // global domain struct. This just makes life easier @@ -110,6 +110,9 @@ vic_start(void) "lake_node"); } + // Validate the parameters file + compare_ncdomain_with_global_domain(filenames.params); + // Check that model parameters are valid validate_parameters(); } From 8f7d656ef3ef4bee9c74015274f8c4545e9c02e8 Mon Sep 17 00:00:00 2001 From: Wietse Franssen Date: Fri, 8 Jul 2016 11:19:11 +0200 Subject: [PATCH 07/33] fixed mpi_rank == VIC_MPI_ROOT --- vic/drivers/shared_image/src/vic_finalize.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vic/drivers/shared_image/src/vic_finalize.c b/vic/drivers/shared_image/src/vic_finalize.c index fdcb1e8f6..cc643876f 100644 --- a/vic/drivers/shared_image/src/vic_finalize.c +++ b/vic/drivers/shared_image/src/vic_finalize.c @@ -64,7 +64,7 @@ vic_finalize(void) int status; - if (mpi_rank == 0) { + if (mpi_rank == VIC_MPI_ROOT) { // close the global parameter file fclose(filep.globalparam); From c620e19b62b0f2cd6626c7330f16a40963fbc23e Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Fri, 8 Jul 2016 08:17:32 -0700 Subject: [PATCH 08/33] read/write state file and rpointer file in cesm driver (#556) --- vic/drivers/cesm/src/cesm_interface_c.c | 5 +- vic/drivers/cesm/src/get_global_param.c | 10 +++ .../cesm/src/vic_populate_model_state.c | 64 ++++++++++++++----- vic/drivers/image/src/vic_image.c | 6 +- .../include/vic_driver_shared_image.h | 2 +- vic/drivers/shared_image/src/vic_store.c | 4 +- 6 files changed, 68 insertions(+), 23 deletions(-) diff --git a/vic/drivers/cesm/src/cesm_interface_c.c b/vic/drivers/cesm/src/cesm_interface_c.c index 7cc68c20b..e8ab846fc 100644 --- a/vic/drivers/cesm/src/cesm_interface_c.c +++ b/vic/drivers/cesm/src/cesm_interface_c.c @@ -102,6 +102,8 @@ vic_cesm_init(vic_clock *vclock, int vic_cesm_run(vic_clock *vclock) { + char state_filename[MAXSTRING]; + // reset l2x fields initialize_l2x_data(); @@ -119,7 +121,8 @@ vic_cesm_run(vic_clock *vclock) // if save: if (vclock->state_flag) { - vic_store(&dmy_current); + vic_store(&dmy_current, state_filename); + write_rpointer_file(state_filename); } // reset x2l fields diff --git a/vic/drivers/cesm/src/get_global_param.c b/vic/drivers/cesm/src/get_global_param.c index 0d03d3e10..7cc7c7459 100644 --- a/vic/drivers/cesm/src/get_global_param.c +++ b/vic/drivers/cesm/src/get_global_param.c @@ -240,6 +240,16 @@ get_global_param(FILE *gp) else if (strcasecmp("LOG_DIR", optstr) == 0) { sscanf(cmdstr, "%*s %s", filenames.log_path); } + else if (strcasecmp("INIT_STATE", optstr) == 0) { + sscanf(cmdstr, "%*s %s", flgstr); + if (strcasecmp("FALSE", flgstr) == 0) { + options.INIT_STATE = false; + } + else { + options.INIT_STATE = true; + strcpy(filenames.init_state, flgstr); + } + } // Define state file format else if (strcasecmp("STATE_FORMAT", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); diff --git a/vic/drivers/cesm/src/vic_populate_model_state.c b/vic/drivers/cesm/src/vic_populate_model_state.c index caba92974..4281d034e 100644 --- a/vic/drivers/cesm/src/vic_populate_model_state.c +++ b/vic/drivers/cesm/src/vic_populate_model_state.c @@ -48,21 +48,32 @@ vic_populate_model_state(char *runtype_str) runtype = start_type_from_char(runtype_str); - // read the model state from the netcdf file if there is one + // read the model state from the netcdf file if (runtype == CESM_RUNTYPE_RESTART || runtype == CESM_RUNTYPE_BRANCH) { // Get restart file from rpointer file read_rpointer_file(filenames.init_state); - // read initial state file + // set options.INIT_STATE to true since we have found a state file in + // the rpointer file. + options.INIT_STATE = true; + + // read initial state file -- specified in rpointer file vic_restore(); } else if (runtype == CESM_RUNTYPE_CLEANSTART) { - // run type is clean start - for (i = 0; i < local_domain.ncells_active; i++) { - generate_default_state(&(all_vars[i]), &(soil_con[i]), veg_con[i]); - if (options.LAKES) { - generate_default_lake_state(&(all_vars[i]), &(soil_con[i]), - lake_con[i]); + if (options.INIT_STATE) { + // read initial state file -- specified in global param file + vic_restore(); + } + else { + // no initial state file specified - generate default state + for (i = 0; i < local_domain.ncells_active; i++) { + generate_default_state(&(all_vars[i]), &(soil_con[i]), + veg_con[i]); + if (options.LAKES) { + generate_default_lake_state(&(all_vars[i]), &(soil_con[i]), + lake_con[i]); + } } } } @@ -105,20 +116,39 @@ void read_rpointer_file(char *fname) { FILE *fp = NULL; + char linestr[MAXSTRING]; - fname = NULL; + fp = open_file(RPOINTER, "r"); - fp = fopen(RPOINTER, "r"); + fgets(linestr, MAXSTRING, fp); - if (fp == NULL) { - log_err("Error reading rpointer file %s", RPOINTER); + // Read through rpointer file file to find state file name + while (!feof(fp)) { + if (linestr[0] != '#' && linestr[0] != '\n' && linestr[0] != '\0') { + sscanf(linestr, "%s", fname); + break; + } + fgets(linestr, MAXSTRING, fp); } + fclose(fp); - fgets(fname, MAXSTRING, fp); + // remove trailing newline if present + fname[strcspn(fname, "\n")] = 0; +} - fclose(fp); +/****************************************************************************** + * @brief Write rpointer file + *****************************************************************************/ +void +write_rpointer_file(char *fname) +{ + FILE *fp = NULL; + char *header = "# VIC CESM Driver restart pointer file\n"; - if (fname == NULL) { - log_err("Error reading rpointer file %s", RPOINTER); - } + fp = open_file(RPOINTER, "w"); + + fprintf(fp, header, fname); + fprintf(fp, "%s\n", fname); + + fclose(fp); } diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index deac3d431..1d45040f5 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -77,7 +77,8 @@ int main(int argc, char **argv) { - int status; + int status; + char state_filename[MAXSTRING]; // Initialize MPI - note: logging not yet initialized status = MPI_Init(&argc, &argv); @@ -125,7 +126,8 @@ main(int argc, // Write state file if (check_save_state_flag(current)) { - vic_store(&(dmy[current])); + vic_store(&(dmy[current]), state_filename); + debug("finished storing state file: %s", state_filename) } } diff --git a/vic/drivers/shared_image/include/vic_driver_shared_image.h b/vic/drivers/shared_image/include/vic_driver_shared_image.h index dc0d92543..3711e1bd0 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -251,7 +251,7 @@ void vic_init(void); void vic_init_output(dmy_struct *dmy_current); void vic_restore(void); void vic_start(void); -void vic_store(dmy_struct *dmy_current); +void vic_store(dmy_struct *dmy_current, char *state_filename); void vic_write(stream_struct *stream, nc_file_struct *nc_hist_file, dmy_struct *dmy_current); void vic_write_output(dmy_struct *dmy); diff --git a/vic/drivers/shared_image/src/vic_store.c b/vic/drivers/shared_image/src/vic_store.c index a984ce737..f032e1c76 100644 --- a/vic/drivers/shared_image/src/vic_store.c +++ b/vic/drivers/shared_image/src/vic_store.c @@ -30,7 +30,8 @@ * @brief Save model state. *****************************************************************************/ void -vic_store(dmy_struct *dmy_current) +vic_store(dmy_struct *dmy_current, + char *filename) { extern filenames_struct filenames; extern all_vars_struct *all_vars; @@ -39,7 +40,6 @@ vic_store(dmy_struct *dmy_current) extern veg_con_map_struct *veg_con_map; extern int mpi_rank; - char filename[MAXSTRING]; int status; int v; size_t i; From 3dfeec06cca86366bb77d70eba0cae077f626d3d Mon Sep 17 00:00:00 2001 From: Wietse Franssen Date: Fri, 8 Jul 2016 17:57:44 +0200 Subject: [PATCH 09/33] 'check_alloc_status(dvar' should be 'check_alloc_status(dvar_filtered'. fixed now --- vic/drivers/shared_image/src/vic_mpi_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index ff1d06529..4636975f1 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -2067,7 +2067,7 @@ get_scatter_nc_field_double(char *nc_name, dvar_filtered = malloc(global_domain.ncells_active * sizeof(*dvar_filtered)); - check_alloc_status(dvar, "Memory allocation error."); + check_alloc_status(dvar_filtered, "Memory allocation error."); dvar_mapped = malloc(global_domain.ncells_active * sizeof(*dvar_mapped)); From 764fe37083aa890486c79ef7cc5d9cecf43db51d Mon Sep 17 00:00:00 2001 From: Wietse Franssen Date: Fri, 8 Jul 2016 18:01:56 +0200 Subject: [PATCH 10/33] fixed hardcoded mpi path in Makefile --- vic/drivers/image/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vic/drivers/image/Makefile b/vic/drivers/image/Makefile index 103a8832a..1984ff666 100644 --- a/vic/drivers/image/Makefile +++ b/vic/drivers/image/Makefile @@ -69,7 +69,7 @@ SHELL = /bin/bash ifeq (true, ${TRAVIS}) CC = ${MPIPATH}/bin/mpicc else ifeq ($(UNAME_S), Linux) -CC = /usr/lib64/mpich/bin/mpicc +CC = ${MPIPATH}/bin/mpicc else CC = mpicc endif From 5e9d8a313a77b000bec19b4bf3b4df1c2c1f3e13 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Mon, 11 Jul 2016 17:58:41 -0700 Subject: [PATCH 11/33] Profiling: Feature/timing (#520) * add timing module to image and classic drivers * update release notes * supress valgrind errors from non-vic libraries --- ci/vic_install_utils | 2 + docs/Development/ReleaseNotes.md | 12 +- tests/run_tests.py | 8 +- .../global.classic.STEHE.allhistvars.txt | 2 + .../system/global.image.STEHE.allhistvars.txt | 2 + tests/unit/shared/test_timing.py | 37 +++++ tests/vic_valgrind_suppressions.supp | 78 ++++++++++ vic/drivers/cesm/src/cesm_interface_c.c | 33 ++++ .../classic/include/vic_driver_classic.h | 1 + vic/drivers/classic/src/vic_classic.c | 32 +++- vic/drivers/classic/src/vic_classic_timing.c | 138 +++++++++++++++++ vic/drivers/image/src/vic_image.c | 27 +++- .../include/vic_driver_shared_all.h | 38 ++++- vic/drivers/shared_all/src/history_metadata.c | 17 ++ vic/drivers/shared_all/src/put_data.c | 12 +- vic/drivers/shared_all/src/timing.c | 97 ++++++++++++ .../include/vic_driver_shared_image.h | 1 + vic/drivers/shared_image/src/vic_image_run.c | 8 +- .../shared_image/src/vic_image_timing.c | 146 ++++++++++++++++++ .../shared_image/src/vic_init_output.c | 5 +- vic/vic_run/include/vic_def.h | 7 + 21 files changed, 686 insertions(+), 17 deletions(-) create mode 100644 tests/unit/shared/test_timing.py create mode 100644 tests/vic_valgrind_suppressions.supp create mode 100644 vic/drivers/classic/src/vic_classic_timing.c create mode 100644 vic/drivers/shared_all/src/timing.c create mode 100644 vic/drivers/shared_image/src/vic_image_timing.c diff --git a/ci/vic_install_utils b/ci/vic_install_utils index 12ac5d84e..a4bca718e 100644 --- a/ci/vic_install_utils +++ b/ci/vic_install_utils @@ -7,6 +7,8 @@ if [ -z "$WORKDIR" ]; then mkdir -p $WORKDIR fi +export VIC_VALGRIND_SUPPRESSIONS=${TRAVIS_BUILD_DIR}/tests/vic_valgrind_suppressions.supp + function install_mpich { wget --no-check-certificate -q http://www.mpich.org/static/downloads/3.2/mpich-3.2.tar.gz tar -xzf mpich-3.2.tar.gz diff --git a/docs/Development/ReleaseNotes.md b/docs/Development/ReleaseNotes.md index 4cd893a77..641a70109 100644 --- a/docs/Development/ReleaseNotes.md +++ b/docs/Development/ReleaseNotes.md @@ -66,6 +66,10 @@ This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly ide A comprehensive testing platform has been implemented and is available for public use along with the VIC model. A small subset of the test platform is run on [Travis-CI](https://travis-ci.org/UW-Hydro/VIC), which facilitates continuous integration of the VIC test platform. More information on the test platform is [here](Testing.md) +11. Run-time profiling and timing ([GH#442](https://github.com/UW-Hydro/VIC/pull/442)) + + A timing module has been added to VIC in order to assess the computational cost and throughput of the VIC model. New output variables (`OUT_TIME_VICRUN_WALL` and `OUT_TIME_VICRUN_CPU`) document the time spent in `vic_run` for each variable. Additionally, a timing table is printed to `LOG_DEST` at the end of each simulation. + #### Backwards Incompatible Changes: 1. Classic Driver I/O Formatting ([GH#18](https://github.com/UW-Hydro/VIC/issues/18), [GH#204](https://github.com/UW-Hydro/VIC/issues/204), [GH#227](https://github.com/UW-Hydro/VIC/pull/227)) @@ -155,13 +159,17 @@ This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly ide 3. Fix related to exact restart ([GH#481](https://github.com/UW-Hydro/VIC/pull/481), [GH#507](https://github.com/UW-Hydro/VIC/pull/507), [GH#509](https://github.com/UW-Hydro/VIC/pull/509)) - Previously, VIC did not produce the same results (fluxes and states) if a simulation is separated into multiple shorter-period runs by saving the state variables and restarting. This was due to: 1) the MTCLIM algorithm resulted in slightly different sub-daily meteorological variable values for different length of forcing (MTCLIM is deprecated in the current version); 2) a few bugs resulting in inexact restart. The following bugs have been fixed: + Previously, VIC did not produce the same results (fluxes and states) if a simulation was separated into multiple shorter-period runs by saving the state variables and restarting. This was due to: + 1. The MTCLIM algorithm resulted in slightly different sub-daily meteorological variable values for different lengths of forcings (MTCLIM is deprecated in the current version) + 2. A few bugs resulting in inexact restart. + + The following bugs have been fixed: - The prognostic state variable `energy.Tfoliage` (foliage temperature) is now saved to the state file - Two flux variables `energy.LongUnderOut` and `energy.snow_flux` are now saved to the state file. !!!Note - This is a temporary solution to ensure exact restart. A better way of handling the two flux variables needs to be done in the future (see [GH#479](https://github.com/UW-Hydro/VIC/issues/479)) + This is a temporary solution to ensure exact restart. A better way of handling these two flux variables needs to be done in the future (see [GH#479](https://github.com/UW-Hydro/VIC/issues/479)) 4. Fix for binary state file I/O ([GH#487](https://github.com/UW-Hydro/VIC/pull/487)) diff --git a/tests/run_tests.py b/tests/run_tests.py index 31faba85a..cdda2d4aa 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -13,7 +13,7 @@ import pytest -from tonic.models.vic.vic import VIC +from tonic.models.vic.vic import VIC, default_vic_valgrind_suppressions_path from tonic.io import read_config, read_configobj from tonic.testing import VICTestError from test_utils import (setup_test_dirs, print_test_dict, @@ -32,6 +32,12 @@ test_dir = os.path.dirname(os.path.abspath(__file__)) +# Set path to valgrind supressions file if not already set. +if 'VIC_VALGRIND_SUPPRESSIONS' not in os.environ: + sup_file = os.path.join(test_dir, default_vic_valgrind_suppressions_path) + if os.path.isfile(sup_file): + os.environ["VIC_VALGRIND_SUPPRESSIONS"] = sup_file + OUTPUT_WIDTH = 100 description = ''' diff --git a/tests/system/global.classic.STEHE.allhistvars.txt b/tests/system/global.classic.STEHE.allhistvars.txt index 77aa0f6c6..92dcc59ea 100644 --- a/tests/system/global.classic.STEHE.allhistvars.txt +++ b/tests/system/global.classic.STEHE.allhistvars.txt @@ -216,3 +216,5 @@ OUTVAR OUT_SNOW_MELT_BAND OUTVAR OUT_SNOW_PACKT_BAND OUTVAR OUT_SNOW_SURFT_BAND OUTVAR OUT_SWE_BAND +OUTVAR OUT_TIME_VICRUN_WALL +OUTVAR OUT_TIME_VICRUN_CPU diff --git a/tests/system/global.image.STEHE.allhistvars.txt b/tests/system/global.image.STEHE.allhistvars.txt index 328f06909..4b29b7afc 100644 --- a/tests/system/global.image.STEHE.allhistvars.txt +++ b/tests/system/global.image.STEHE.allhistvars.txt @@ -204,3 +204,5 @@ OUTVAR OUT_SNOW_MELT_BAND OUTVAR OUT_SNOW_PACKT_BAND OUTVAR OUT_SNOW_SURFT_BAND OUTVAR OUT_SWE_BAND +OUTVAR OUT_TIME_VICRUN_WALL +OUTVAR OUT_TIME_VICRUN_CPU diff --git a/tests/unit/shared/test_timing.py b/tests/unit/shared/test_timing.py new file mode 100644 index 000000000..6856a4e01 --- /dev/null +++ b/tests/unit/shared/test_timing.py @@ -0,0 +1,37 @@ +import time + +from vic.vic import ffi +from vic import lib as vic_lib + + +def test_vic_timers(): + + timer = ffi.new('timer_struct *') + sleeptime = 1.5 + delta = 0.1 + + # init sets delta to zero + vic_lib.timer_init(timer) + + # start gets current time + vic_lib.timer_start(timer) + + # sleep + time.sleep(sleeptime) + + # stop pauses the timer + vic_lib.timer_stop(timer) + assert timer[0].delta_wall >= sleeptime + assert timer[0].delta_wall < sleeptime + delta + assert timer[0].delta_cpu >= 0. + + # start the timer again + vic_lib.timer_continue(timer) + + # sleep again + time.sleep(sleeptime) + + # stop after the lap time sleep + vic_lib.timer_stop(timer) + assert timer[0].delta_wall >= 2 * sleeptime + assert timer[0].delta_wall < 2 * (sleeptime + delta) diff --git a/tests/vic_valgrind_suppressions.supp b/tests/vic_valgrind_suppressions.supp new file mode 100644 index 000000000..7ad498fe9 --- /dev/null +++ b/tests/vic_valgrind_suppressions.supp @@ -0,0 +1,78 @@ +# +# This is a valgrind suppression file that should be used when using valgrind. +# It is used to keep valgrind from reporting errors on known errors in libraries +# VIC uses. +# +# Here's an example of running valgrind: +# +# cd vic/drivers/classic +# valgrind -v --leak-check=full --error-exitcode=125 \ +# --suppressions=vic_valgrind_supressions.supp vic_classic.exe -g global_param.txt +# +# all tool names: Addrcheck,Memcheck,cachegrind,helgrind,massif +# + +{ + supress_dispatch_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:dispatch_once_f + ... +} +{ + supress_getpwuid1_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:getpwuid + ... +} +{ + supress_localtime_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:localtime + ... +} +{ + supress_bootstrap_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:bootstrap_look_up3 + ... +} +{ + supress_sprintf_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:__sprintf_chk + ... +} +{ + supress_sscanf_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:sscanf + ... +} +{ + supress_stringcopy_not_vic_specific + Memcheck:Leak + # match-leak-kinds: possible + ... + fun:_ZL22copySwiftV1MangledNamePKcb + ... +} +{ + supress_getpwuid_r_not_vic_specific + Memcheck:Leak + # match-leak-kinds: definite + ... + fun:getpwuid_r + ... +} diff --git a/vic/drivers/cesm/src/cesm_interface_c.c b/vic/drivers/cesm/src/cesm_interface_c.c index e8ab846fc..92224effd 100644 --- a/vic/drivers/cesm/src/cesm_interface_c.c +++ b/vic/drivers/cesm/src/cesm_interface_c.c @@ -67,6 +67,7 @@ save_data_struct *save_data; // [ncells] double ***out_data = NULL; // [ncells, nvars, nelem] stream_struct *output_streams = NULL; // [nstreams] nc_file_struct *nc_hist_files = NULL; // [nstreams] +timer_struct global_timers[N_TIMERS]; /****************************************************************************** * @brief Initialization function for CESM driver @@ -75,6 +76,11 @@ int vic_cesm_init(vic_clock *vclock, case_metadata *cmeta) { + // start vic all timer + timer_start(&(global_timers[TIMER_VIC_ALL])); + // start vic init timer + timer_start(&(global_timers[TIMER_VIC_INIT])); + // read global parameters vic_cesm_start(vclock, cmeta); @@ -93,6 +99,11 @@ vic_cesm_init(vic_clock *vclock, // initialize output structures vic_init_output(&dmy_current); + // stop init timer + timer_stop(&(global_timers[TIMER_VIC_INIT])); + // stop vic all timer + timer_stop(&(global_timers[TIMER_VIC_ALL])); + return EXIT_SUCCESS; } @@ -104,6 +115,11 @@ vic_cesm_run(vic_clock *vclock) { char state_filename[MAXSTRING]; + // continue vic all timer + timer_continue(&(global_timers[TIMER_VIC_ALL])); + // start vic run timer + timer_start(&(global_timers[TIMER_VIC_RUN])); + // reset l2x fields initialize_l2x_data(); @@ -132,6 +148,11 @@ vic_cesm_run(vic_clock *vclock) advance_time(); assert_time_insync(vclock, &dmy_current); + // stop vic run timer + timer_stop(&(global_timers[TIMER_VIC_RUN])); + // stop vic all timer + timer_stop(&(global_timers[TIMER_VIC_ALL])); + return EXIT_SUCCESS; } @@ -141,8 +162,20 @@ vic_cesm_run(vic_clock *vclock) int vic_cesm_final() { + // continue vic all timer + timer_continue(&(global_timers[TIMER_VIC_ALL])); + // start vic run timer + timer_start(&(global_timers[TIMER_VIC_RUN])); + // clean up vic_cesm_finalize(); + // stop vic final timer + timer_stop(&(global_timers[TIMER_VIC_FINAL])); + // stop vic all timer + timer_stop(&(global_timers[TIMER_VIC_ALL])); + // write timing info + write_vic_timing_table(global_timers, VIC_DRIVER); + return EXIT_SUCCESS; } diff --git a/vic/drivers/classic/include/vic_driver_classic.h b/vic/drivers/classic/include/vic_driver_classic.h index 634b15831..d7365f6bf 100644 --- a/vic/drivers/classic/include/vic_driver_classic.h +++ b/vic/drivers/classic/include/vic_driver_classic.h @@ -117,4 +117,5 @@ void write_header(stream_struct **streams, dmy_struct *dmy); void write_model_state(all_vars_struct *, int, int, filep_struct *, soil_con_struct *); void write_output(stream_struct **streams, dmy_struct *dmy); +void write_vic_timing_table(timer_struct *timers); #endif diff --git a/vic/drivers/classic/src/vic_classic.c b/vic/drivers/classic/src/vic_classic.c index ef6a65ce3..6be6111d8 100644 --- a/vic/drivers/classic/src/vic_classic.c +++ b/vic/drivers/classic/src/vic_classic.c @@ -77,6 +77,13 @@ main(int argc, stream_struct *streams = NULL; double ***out_data; // [1, nvars, nelem] save_data_struct save_data; + timer_struct global_timers[N_TIMERS]; + timer_struct cell_timer; + + // start vic all timer + timer_start(&(global_timers[TIMER_VIC_ALL])); + // start vic init timer + timer_start(&(global_timers[TIMER_VIC_INIT])); // Initialize Log Destination initialize_log(); @@ -155,6 +162,12 @@ main(int argc, Run Model for all Active Grid Cells ************************************/ MODEL_DONE = false; + + // stop init timer + timer_stop(&(global_timers[TIMER_VIC_INIT])); + // start vic run timer + timer_start(&(global_timers[TIMER_VIC_RUN])); + while (!MODEL_DONE) { read_soilparam(filep.soilparam, &soil_con, &RUN_MODEL, &MODEL_DONE); @@ -201,7 +214,8 @@ main(int argc, /** Initialize the storage terms in the water and energy balances **/ initialize_save_data(&all_vars, &force[0], &soil_con, veg_con, - veg_lib, &lake_con, out_data[0], &save_data); + veg_lib, &lake_con, out_data[0], &save_data, + &cell_timer); /****************************************** Run Model in Grid Cell for all Time Steps @@ -223,15 +237,17 @@ main(int argc, /************************************************** Compute cell physics for 1 timestep **************************************************/ + timer_start(&cell_timer); ErrorFlag = vic_run(&force[rec], &all_vars, &(dmy[rec]), &global_param, &lake_con, &soil_con, veg_con, veg_lib); + timer_stop(&cell_timer); /************************************************** Calculate cell average values for current time step **************************************************/ put_data(&all_vars, &force[rec], &soil_con, veg_con, veg_lib, - &lake_con, out_data[0], &save_data); + &lake_con, out_data[0], &save_data, &cell_timer); for (streamnum = 0; streamnum < options.Noutstreams; @@ -289,6 +305,11 @@ main(int argc, } /* End Run Model Condition */ } /* End Grid Loop */ + // stop vic run timer + timer_stop(&(global_timers[TIMER_VIC_RUN])); + // start vic final timer + timer_start(&(global_timers[TIMER_VIC_FINAL])); + /** cleanup **/ free_atmos(global_param.nrecs, &force); free_dmy(&dmy); @@ -314,5 +335,12 @@ main(int argc, log_info("Completed running VIC %s", VIC_DRIVER); + // stop vic final timer + timer_stop(&(global_timers[TIMER_VIC_FINAL])); + // stop vic all timer + timer_stop(&(global_timers[TIMER_VIC_ALL])); + // write timing info + write_vic_timing_table(global_timers); + return EXIT_SUCCESS; } /* End Main Program */ diff --git a/vic/drivers/classic/src/vic_classic_timing.c b/vic/drivers/classic/src/vic_classic_timing.c new file mode 100644 index 000000000..0a4cae832 --- /dev/null +++ b/vic/drivers/classic/src/vic_classic_timing.c @@ -0,0 +1,138 @@ +/****************************************************************************** + * @section DESCRIPTION + * + * Write vic timing table for classic driver + * + * @section LICENSE + * + * The Variable Infiltration Capacity (VIC) macroscale hydrological model + * Copyright (C) 2016 The Computational Hydrology Group, Department of Civil + * and Environmental Engineering, University of Washington. + * + * The VIC model is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *****************************************************************************/ + +#include + +/****************************************************************************** + * @brief VIC timing file + *****************************************************************************/ +void +write_vic_timing_table(timer_struct *timers) +{ + extern FILE *LOG_DEST; + extern filenames_struct filenames; + extern global_param_struct global_param; + + char machine[MAXSTRING]; + char user[MAXSTRING]; + time_t curr_date_time; + struct tm *timeinfo; + uid_t uid; + struct passwd *pw; + double ndays; + double nyears; + + // datestr + curr_date_time = time(NULL); + if (curr_date_time == -1) { + log_err("Failed to get the current time!"); + } + timeinfo = localtime(&curr_date_time); + + // hostname + if (gethostname(machine, MAXSTRING) != 0) { + strcpy(machine, "unknown"); + } + + // username + uid = geteuid(); + pw = getpwuid(uid); + + if (pw) { + strcpy(user, pw->pw_name); + } + else { + strcpy(user, "unknown"); + } + + // calculate run length + ndays = global_param.dt * global_param.nrecs / SEC_PER_DAY; + nyears = ndays / DAYS_PER_YEAR; + + fprintf(LOG_DEST, "\n"); + fprintf(LOG_DEST, + "------------------------------" + " VIC TIMING PROFILE " + "------------------------------\n\n"); + fprintf(LOG_DEST, " Date : %s", asctime(timeinfo)); + fprintf(LOG_DEST, " Compiler : %s (%s)\n", COMPILER, + COMPILER_VERSION); + fprintf(LOG_DEST, " Machine : %s\n", machine); + fprintf(LOG_DEST, " VIC User : %s\n", user); + fprintf(LOG_DEST, " VIC Version : %s\n", GIT_VERSION); + fprintf(LOG_DEST, " VIC GIT Version : %s\n", VERSION); + fprintf(LOG_DEST, " VIC_DRIVER : %s\n", VIC_DRIVER); + fprintf(LOG_DEST, "\n"); + fprintf(LOG_DEST, " Global Param File : %s\n", filenames.global); + fprintf(LOG_DEST, " Start Date : %04hu-%02hu-%02hu-%05u\n", + global_param.startyear, global_param.startmonth, + global_param.startday, global_param.startsec); + fprintf(LOG_DEST, " Stop Date : %04hu-%02hu-%02hu\n", + global_param.endyear, global_param.endmonth, global_param.endday); + fprintf(LOG_DEST, " Nrecs : %zu\n", + global_param.nrecs); + fprintf(LOG_DEST, " Model Timestep (seconds) : %g\n", global_param.dt); + fprintf(LOG_DEST, " Snow Timestep (seconds) : %g\n", + global_param.snow_dt); + fprintf(LOG_DEST, " Runoff Timestep (seconds) : %g\n", + global_param.runoff_dt); + fprintf(LOG_DEST, " Atmos Timestep (seconds) : %g\n", + global_param.atmos_dt); + fprintf(LOG_DEST, "\n"); + + fprintf(LOG_DEST, "\n"); + + fprintf(LOG_DEST, " Overall Metrics\n"); + fprintf(LOG_DEST, " ---------------\n"); + fprintf(LOG_DEST, " Model Cost : %g pe-hrs/simulated_year\n", + timers[TIMER_VIC_ALL].delta_wall / SEC_PER_HOUR / nyears); + fprintf(LOG_DEST, " Model Throughput : %g simulated_years/day\n", + nyears / (timers[TIMER_VIC_ALL].delta_wall / SEC_PER_DAY)); + fprintf(LOG_DEST, "\n"); + fprintf(LOG_DEST, " Timing Table:\n"); + fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "| Timer | Wall Time (secs) | CPU Time (secs) | Wall Time (secs/day) | CPU Time (secs/day) |\n"); + fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "| Init Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_INIT].delta_wall, timers[TIMER_VIC_INIT].delta_cpu, + timers[TIMER_VIC_INIT].delta_wall / ndays, timers[TIMER_VIC_INIT].delta_cpu / ndays); + fprintf(LOG_DEST, "| Run Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_RUN].delta_wall, timers[TIMER_VIC_RUN].delta_cpu, + timers[TIMER_VIC_RUN].delta_wall / ndays, timers[TIMER_VIC_RUN].delta_cpu / ndays); + fprintf(LOG_DEST, "| Final Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_FINAL].delta_wall, timers[TIMER_VIC_FINAL].delta_cpu, + timers[TIMER_VIC_FINAL].delta_wall / ndays, timers[TIMER_VIC_FINAL].delta_cpu / ndays); + fprintf(LOG_DEST, "| Total Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_ALL].delta_wall, timers[TIMER_VIC_ALL].delta_cpu, + timers[TIMER_VIC_ALL].delta_wall / ndays, timers[TIMER_VIC_ALL].delta_cpu / ndays); + fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "\n"); + + fprintf(LOG_DEST, + "\n------------------------------" + " END VIC TIMING PROFILE " + "------------------------------\n\n"); +} diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index 1d45040f5..75be0ec73 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -77,8 +77,14 @@ int main(int argc, char **argv) { - int status; - char state_filename[MAXSTRING]; + int status; + timer_struct global_timers[N_TIMERS]; + char state_filename[MAXSTRING]; + + // start vic all timer + timer_start(&(global_timers[TIMER_VIC_ALL])); + // start vic init timer + timer_start(&(global_timers[TIMER_VIC_INIT])); // Initialize MPI - note: logging not yet initialized status = MPI_Init(&argc, &argv); @@ -113,6 +119,11 @@ main(int argc, // initialize output structures vic_init_output(&(dmy[0])); + // stop init timer + timer_stop(&(global_timers[TIMER_VIC_INIT])); + // start vic run timer + timer_start(&(global_timers[TIMER_VIC_RUN])); + // loop over all timesteps for (current = 0; current < global_param.nrecs; current++) { // read forcing data @@ -130,7 +141,10 @@ main(int argc, debug("finished storing state file: %s", state_filename) } } - + // stop vic run timer + timer_stop(&(global_timers[TIMER_VIC_RUN])); + // start vic final timer + timer_start(&(global_timers[TIMER_VIC_FINAL])); // clean up vic_image_finalize(); @@ -142,5 +156,12 @@ main(int argc, log_info("Completed running VIC %s", VIC_DRIVER); + // stop vic final timer + timer_stop(&(global_timers[TIMER_VIC_FINAL])); + // stop vic all timer + timer_stop(&(global_timers[TIMER_VIC_ALL])); + // write timing info + write_vic_timing_table(global_timers, VIC_DRIVER); + return EXIT_SUCCESS; } diff --git a/vic/drivers/shared_all/include/vic_driver_shared_all.h b/vic/drivers/shared_all/include/vic_driver_shared_all.h index e832b88cc..c4a98fa94 100644 --- a/vic/drivers/shared_all/include/vic_driver_shared_all.h +++ b/vic/drivers/shared_all/include/vic_driver_shared_all.h @@ -279,6 +279,9 @@ enum OUT_CLITTER, /**< Carbon density in litter pool [g C/m2] */ OUT_CINTER, /**< Carbon density in intermediate pool [g C/m2] */ OUT_CSLOW, /**< Carbon density in slow pool [g C/m2] */ + // Timing and Profiling Terms + OUT_TIME_VICRUN_WALL, /**< Wall time spent inside vic_run [seconds] */ + OUT_TIME_VICRUN_CPU, /**< Wall time spent inside vic_run [seconds] */ // Last value of enum - DO NOT ADD ANYTHING BELOW THIS LINE!! // used as a loop counter and must be >= the largest value in this enum N_OUTVAR_TYPES /**< used as a loop counter*/ @@ -439,6 +442,18 @@ enum time_units TIME_UNITS_DAYS }; +/****************************************************************************** + * @brief Codes for timers + *****************************************************************************/ +enum timers +{ + TIMER_VIC_ALL, + TIMER_VIC_INIT, + TIMER_VIC_RUN, + TIMER_VIC_FINAL, + N_TIMERS +}; + /****************************************************************************** * @brief Stores forcing file input information. *****************************************************************************/ @@ -548,6 +563,18 @@ typedef struct { veg_var_struct *veg_var; } Error_struct; +/****************************************************************************** + * @brief This structure holds timer information for profiling + *****************************************************************************/ +typedef struct { + double start_wall; + double start_cpu; + double stop_wall; + double stop_cpu; + double delta_wall; + double delta_cpu; +} timer_struct; + double air_density(double t, double p); void agg_stream_data(stream_struct *stream, dmy_struct *dmy_current, double ***out_data); @@ -577,7 +604,9 @@ void count_nstreams_nvars(FILE *gp, size_t *nstreams, size_t nvars[]); void cmd_proc(int argc, char **argv, char *globalfilename); void compress_files(char string[], short int level); stream_struct create_outstream(stream_struct *output_streams); +double get_cpu_time(); void get_current_datetime(char *cdt); +double get_wall_time(); double date2num(double origin, dmy_struct *date, double tzoffset, unsigned short int calendar, unsigned short int time_units); void dmy_all_30_day(double julian, dmy_struct *dmy); @@ -610,7 +639,8 @@ void initialize_parameters(void); void initialize_save_data(all_vars_struct *all_vars, force_data_struct *force, soil_con_struct *soil_con, veg_con_struct *veg_con, veg_lib_struct *veg_lib, lake_con_struct *lake_con, - double **out_data, save_data_struct *save_data); + double **out_data, save_data_struct *save_data, + timer_struct *timer); void initialize_snow(snow_data_struct **snow, size_t veg_num); void initialize_soil(cell_data_struct **cell, size_t veg_num); void initialize_time(void); @@ -634,7 +664,7 @@ void parse_nc_time_units(char *nc_unit_chars, unsigned short int *units, dmy_struct *dmy); void put_data(all_vars_struct *, force_data_struct *, soil_con_struct *, veg_con_struct *, veg_lib_struct *veg_lib, lake_con_struct *, - double **out_data, save_data_struct *); + double **out_data, save_data_struct *, timer_struct *timer); void print_alarm(alarm_struct *alarm); void print_cell_data(cell_data_struct *cell, size_t nlayers, size_t nfrost); void print_dmy(dmy_struct *dmy); @@ -693,6 +723,10 @@ unsigned short int str_to_out_type(char typestr[]); unsigned short int str_to_timeunits(char units_chars[]); void strpdmy(const char *s, const char *format, dmy_struct *dmy); double time_delta(dmy_struct *dmy_current, unsigned short int freq, int n); +void timer_continue(timer_struct *t); +void timer_init(timer_struct *t); +void timer_start(timer_struct *t); +void timer_stop(timer_struct *t); int update_step_vars(all_vars_struct *, veg_con_struct *, veg_hist_struct *); int invalid_date(unsigned short int calendar, dmy_struct *dmy); void validate_parameters(void); diff --git a/vic/drivers/shared_all/src/history_metadata.c b/vic/drivers/shared_all/src/history_metadata.c index 7bd03b5e1..93a40aab2 100644 --- a/vic/drivers/shared_all/src/history_metadata.c +++ b/vic/drivers/shared_all/src/history_metadata.c @@ -1459,6 +1459,23 @@ set_output_met_data_info() strcpy(out_metadata[OUT_SWE_BAND].description, out_metadata[OUT_SWE].description); + /* Wall time spent inside vic_run [seconds] */ + strcpy(out_metadata[OUT_TIME_VICRUN_WALL].varname, "OUT_TIME_VICRUN_WALL"); + strcpy(out_metadata[OUT_TIME_VICRUN_WALL].long_name, "time_vicrun_wall"); + strcpy(out_metadata[OUT_TIME_VICRUN_WALL].standard_name, + "vic_run_wall_time"); + strcpy(out_metadata[OUT_TIME_VICRUN_WALL].units, "seconds"); + strcpy(out_metadata[OUT_TIME_VICRUN_WALL].description, + "Wall time spent inside vic_run"); + + /* CPU time spent inside vic_run [seconds] */ + strcpy(out_metadata[OUT_TIME_VICRUN_CPU].varname, "OUT_TIME_VICRUN_CPU"); + strcpy(out_metadata[OUT_TIME_VICRUN_CPU].long_name, "time_vicrun_cpu"); + strcpy(out_metadata[OUT_TIME_VICRUN_CPU].standard_name, "vic_run_cpu_time"); + strcpy(out_metadata[OUT_TIME_VICRUN_CPU].units, "seconds"); + strcpy(out_metadata[OUT_TIME_VICRUN_CPU].description, + "CPU time spent inside vic_run"); + if (options.FROZEN_SOIL) { out_metadata[OUT_FDEPTH].nelem = MAX_FRONTS; out_metadata[OUT_TDEPTH].nelem = MAX_FRONTS; diff --git a/vic/drivers/shared_all/src/put_data.c b/vic/drivers/shared_all/src/put_data.c index 12c6f441f..700310480 100644 --- a/vic/drivers/shared_all/src/put_data.c +++ b/vic/drivers/shared_all/src/put_data.c @@ -39,7 +39,8 @@ put_data(all_vars_struct *all_vars, veg_lib_struct *veg_lib, lake_con_struct *lake_con, double **out_data, - save_data_struct *save_data) + save_data_struct *save_data, + timer_struct *timer) { extern global_param_struct global_param; extern option_struct options; @@ -567,6 +568,10 @@ put_data(all_vars_struct *all_vars, else { out_data[OUT_ENERGY_ERROR][0] = MISSING; } + + // vic_run run time + out_data[OUT_TIME_VICRUN_WALL][0] = timer->delta_wall; + out_data[OUT_TIME_VICRUN_CPU][0] = timer->delta_cpu; } /****************************************************************************** @@ -1052,11 +1057,12 @@ initialize_save_data(all_vars_struct *all_vars, veg_lib_struct *veg_lib, lake_con_struct *lake_con, double **out_data, - save_data_struct *save_data) + save_data_struct *save_data, + timer_struct *timer) { // Calling put data will populate the save data storage terms put_data(all_vars, atmos, soil_con, veg_con, veg_lib, lake_con, - out_data, save_data); + out_data, save_data, timer); zero_output_list(out_data); } diff --git a/vic/drivers/shared_all/src/timing.c b/vic/drivers/shared_all/src/timing.c new file mode 100644 index 000000000..23691785e --- /dev/null +++ b/vic/drivers/shared_all/src/timing.c @@ -0,0 +1,97 @@ +/****************************************************************************** + * @section DESCRIPTION + * + * Routines to calculate and store model runtime timing. + * + * @section LICENSE + * + * The Variable Infiltration Capacity (VIC) macroscale hydrological model + * Copyright (C) 2014 The Land Surface Hydrology Group, Department of Civil + * and Environmental Engineering, University of Washington. + * + * The VIC model is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *****************************************************************************/ + +#include + +/****************************************************************************** + * @brief Get wall time + *****************************************************************************/ +double +get_wall_time() +{ + struct timeval time; + if (gettimeofday(&time, NULL)) { + log_err("get_wall_time failed") + } + return (double) time.tv_sec + (double) time.tv_usec * 0.000001; +} + +/****************************************************************************** + * @brief Get CPU time + *****************************************************************************/ +double +get_cpu_time() +{ + return (double) clock() / CLOCKS_PER_SEC; +} + +/****************************************************************************** + * @brief Initialize timer values + *****************************************************************************/ +void +timer_init(timer_struct *t) +{ + t->start_wall = 0; + t->start_cpu = 0; + + t->delta_wall = 0; + t->delta_cpu = 0; +} + +/****************************************************************************** + * @brief Start timer + *****************************************************************************/ +void +timer_start(timer_struct *t) +{ + timer_init(t); + + t->start_wall = get_wall_time(); + t->start_cpu = get_cpu_time(); +} + +/****************************************************************************** + * @brief Stop timer + *****************************************************************************/ +void +timer_stop(timer_struct *t) +{ + t->stop_wall = get_wall_time(); + t->stop_cpu = get_cpu_time(); + + t->delta_wall += t->stop_wall - t->start_wall; + t->delta_cpu += t->stop_cpu - t->start_cpu; +} + +/****************************************************************************** + * @brief Continue timer without resetting counters + *****************************************************************************/ +void +timer_continue(timer_struct *t) +{ + t->start_wall = get_wall_time(); + t->start_cpu = get_cpu_time(); +} diff --git a/vic/drivers/shared_image/include/vic_driver_shared_image.h b/vic/drivers/shared_image/include/vic_driver_shared_image.h index 3711e1bd0..f8861f2b6 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -255,4 +255,5 @@ void vic_store(dmy_struct *dmy_current, char *state_filename); void vic_write(stream_struct *stream, nc_file_struct *nc_hist_file, dmy_struct *dmy_current); void vic_write_output(dmy_struct *dmy); +void write_vic_timing_table(timer_struct *timers, char *driver); #endif diff --git a/vic/drivers/shared_image/src/vic_image_run.c b/vic/drivers/shared_image/src/vic_image_run.c index dd6f734af..56bccf520 100644 --- a/vic/drivers/shared_image/src/vic_image_run.c +++ b/vic/drivers/shared_image/src/vic_image_run.c @@ -49,6 +49,7 @@ vic_image_run(dmy_struct *dmy_current) char dmy_str[MAXSTRING]; size_t i; + timer_struct timer; // Print the current timestep info before running vic_run sprint_dmy(dmy_str, dmy_current); @@ -60,10 +61,15 @@ vic_image_run(dmy_struct *dmy_current) local_domain.locations[i].io_idx, dmy_str); update_step_vars(&(all_vars[i]), veg_con[i], veg_hist[i]); + + timer_start(&timer); vic_run(&(force[i]), &(all_vars[i]), dmy_current, &global_param, &lake_con, &(soil_con[i]), veg_con[i], veg_lib[i]); + timer_stop(&timer); + put_data(&(all_vars[i]), &(force[i]), &(soil_con[i]), veg_con[i], - veg_lib[i], &lake_con, out_data[i], &(save_data[i])); + veg_lib[i], &lake_con, out_data[i], &(save_data[i]), + &timer); } for (i = 0; i < options.Noutstreams; i++) { agg_stream_data(&(output_streams[i]), dmy_current, out_data); diff --git a/vic/drivers/shared_image/src/vic_image_timing.c b/vic/drivers/shared_image/src/vic_image_timing.c new file mode 100644 index 000000000..acd35cc46 --- /dev/null +++ b/vic/drivers/shared_image/src/vic_image_timing.c @@ -0,0 +1,146 @@ +/****************************************************************************** + * @section DESCRIPTION + * + * Write vic timing table for image-like drivers + * + * @section LICENSE + * + * The Variable Infiltration Capacity (VIC) macroscale hydrological model + * Copyright (C) 2016 The Computational Hydrology Group, Department of Civil + * and Environmental Engineering, University of Washington. + * + * The VIC model is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + *****************************************************************************/ + +#include + +/****************************************************************************** + * @brief VIC timing file + *****************************************************************************/ +void +write_vic_timing_table(timer_struct *timers, + char *driver) +{ + extern FILE *LOG_DEST; + extern filenames_struct filenames; + extern global_param_struct global_param; + extern int mpi_size; + + char machine[MAXSTRING]; + char user[MAXSTRING]; + time_t curr_date_time; + struct tm *timeinfo; + uid_t uid; + struct passwd *pw; + double ndays; + double nyears; + + // datestr + curr_date_time = time(NULL); + if (curr_date_time == -1) { + log_err("Failed to get the current time!"); + } + timeinfo = localtime(&curr_date_time); + + // hostname + if (gethostname(machine, MAXSTRING) != 0) { + strcpy(machine, "unknown"); + } + + // username + uid = geteuid(); + pw = getpwuid(uid); + + if (pw) { + strcpy(user, pw->pw_name); + } + else { + strcpy(user, "unknown"); + } + + // calculate run length + ndays = global_param.dt * global_param.nrecs / SEC_PER_DAY; + nyears = ndays / DAYS_PER_YEAR; + + fprintf(LOG_DEST, "\n"); + fprintf(LOG_DEST, + "------------------------------" + " VIC TIMING PROFILE " + "------------------------------\n\n"); + fprintf(LOG_DEST, " Date : %s", asctime(timeinfo)); + fprintf(LOG_DEST, " Compiler : %s (%s)\n", COMPILER, + COMPILER_VERSION); + fprintf(LOG_DEST, " Machine : %s\n", machine); + fprintf(LOG_DEST, " VIC User : %s\n", user); + fprintf(LOG_DEST, " VIC Version : %s\n", GIT_VERSION); + fprintf(LOG_DEST, " VIC GIT Version : %s\n", VERSION); + fprintf(LOG_DEST, " VIC_DRIVER : %s\n", driver); + fprintf(LOG_DEST, "\n"); + fprintf(LOG_DEST, " Global Param File : %s\n", filenames.global); + fprintf(LOG_DEST, " Domain File : %s\n", filenames.domain); + fprintf(LOG_DEST, " Start Date : %04hu-%02hu-%02hu-%05u\n", + global_param.startyear, global_param.startmonth, + global_param.startday, global_param.startsec); + fprintf(LOG_DEST, " Stop Date : %04hu-%02hu-%02hu\n", + global_param.endyear, global_param.endmonth, global_param.endday); + fprintf(LOG_DEST, " Nrecs : %zu\n", + global_param.nrecs); + fprintf(LOG_DEST, " Model Timestep (seconds) : %g\n", global_param.dt); + fprintf(LOG_DEST, " Snow Timestep (seconds) : %g\n", + global_param.snow_dt); + fprintf(LOG_DEST, " Runoff Timestep (seconds) : %g\n", + global_param.runoff_dt); + fprintf(LOG_DEST, " Atmos Timestep (seconds) : %g\n", + global_param.atmos_dt); + fprintf(LOG_DEST, "\n"); + + fprintf(LOG_DEST, " Total pes active : %d\n", mpi_size); + fprintf(LOG_DEST, " pes per node : %ld\n", + sysconf(_SC_NPROCESSORS_ONLN)); + + fprintf(LOG_DEST, "\n"); + + fprintf(LOG_DEST, " Overall Metrics\n"); + fprintf(LOG_DEST, " ---------------\n"); + fprintf(LOG_DEST, " Model Cost : %g pe-hrs/simulated_year\n", + mpi_size * timers[TIMER_VIC_ALL].delta_wall / SEC_PER_HOUR / + nyears); + fprintf(LOG_DEST, " Model Throughput : %g simulated_years/day\n", + nyears / (timers[TIMER_VIC_ALL].delta_wall / SEC_PER_DAY)); + fprintf(LOG_DEST, "\n"); + fprintf(LOG_DEST, " Timing Table:\n"); + fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "| Timer | Wall Time (secs) | CPU Time (secs) | Wall Time (secs/day) | CPU Time (secs/day) |\n"); + fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "| Init Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_INIT].delta_wall, timers[TIMER_VIC_INIT].delta_cpu, + timers[TIMER_VIC_INIT].delta_wall / ndays, timers[TIMER_VIC_INIT].delta_cpu / ndays); + fprintf(LOG_DEST, "| Run Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_RUN].delta_wall, timers[TIMER_VIC_RUN].delta_cpu, + timers[TIMER_VIC_RUN].delta_wall / ndays, timers[TIMER_VIC_RUN].delta_cpu / ndays); + fprintf(LOG_DEST, "| Final Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_FINAL].delta_wall, timers[TIMER_VIC_FINAL].delta_cpu, + timers[TIMER_VIC_FINAL].delta_wall / ndays, timers[TIMER_VIC_FINAL].delta_cpu / ndays); + fprintf(LOG_DEST, "| Total Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_ALL].delta_wall, timers[TIMER_VIC_ALL].delta_cpu, + timers[TIMER_VIC_ALL].delta_wall / ndays, timers[TIMER_VIC_ALL].delta_cpu / ndays); + fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "\n"); + + fprintf(LOG_DEST, + "\n------------------------------" + " END VIC TIMING PROFILE " + "------------------------------\n\n"); +} diff --git a/vic/drivers/shared_image/src/vic_init_output.c b/vic/drivers/shared_image/src/vic_init_output.c index b1692d559..ca0bbc0d4 100644 --- a/vic/drivers/shared_image/src/vic_init_output.c +++ b/vic/drivers/shared_image/src/vic_init_output.c @@ -24,8 +24,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *****************************************************************************/ -#include -#include #include /****************************************************************************** @@ -57,6 +55,7 @@ vic_init_output(dmy_struct *dmy_current) size_t streamnum; size_t nstream_vars[MAX_OUTPUT_STREAMS]; bool default_outputs = false; + timer_struct timer; // initialize the output data structures set_output_met_data_info(); @@ -68,7 +67,7 @@ vic_init_output(dmy_struct *dmy_current) for (i = 0; i < local_domain.ncells_active; i++) { initialize_save_data(&(all_vars[i]), &(force[i]), &(soil_con[i]), veg_con[i], veg_lib[i], &lake_con, out_data[i], - &(save_data[i])); + &(save_data[i]), &timer); } if (mpi_rank == VIC_MPI_ROOT) { diff --git a/vic/vic_run/include/vic_def.h b/vic/vic_run/include/vic_def.h index d8a462d63..ddeffb3ce 100644 --- a/vic/vic_run/include/vic_def.h +++ b/vic/vic_run/include/vic_def.h @@ -27,6 +27,10 @@ #ifndef VIC_DEF_H #define VIC_DEF_H +#define _BSD_SOURCE +#define __USE_XOPEN +#define _GNU_SOURCE + #include #include #include @@ -38,6 +42,9 @@ #include #include #include +#include +#include +#include #include #include From acbca758d545830ead81f2dba847c10eb8913bcc Mon Sep 17 00:00:00 2001 From: Wietse Franssen Date: Thu, 14 Jul 2016 18:02:52 +0200 Subject: [PATCH 12/33] j and i index should be switched. Fixed now (#562) --- vic/drivers/shared_all/src/vic_history.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vic/drivers/shared_all/src/vic_history.c b/vic/drivers/shared_all/src/vic_history.c index ffd4314a5..1696db343 100644 --- a/vic/drivers/shared_all/src/vic_history.c +++ b/vic/drivers/shared_all/src/vic_history.c @@ -52,7 +52,7 @@ alloc_out_data(size_t ngridcells, check_alloc_status((*out_data)[i][j], "Memory allocation error."); // initialize data member - for (k = 0; k < out_metadata[i].nelem; k++) { + for (k = 0; k < out_metadata[j].nelem; k++) { (*out_data)[i][j][k] = 0; } } From eea8118a4ec1c30652d38e62fad6f0410ead20fe Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Mon, 25 Jul 2016 17:15:15 -0700 Subject: [PATCH 13/33] Cleanup image driver build (#565) * image driver updates for building VIC on hyak, use nc-config to determine netcdf libraries * allow env var specification of netcdf libs and mpicc in image makefile --- .gitignore | 5 +- .travis.yml | 4 ++ ci/image.travis | 18 ++++--- vic/drivers/image/Makefile | 51 ++++++-------------- vic/drivers/shared_all/include/vic_version.h | 2 +- 5 files changed, 35 insertions(+), 45 deletions(-) diff --git a/.gitignore b/.gitignore index 4307a5182..674f2d010 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,8 @@ vic_headers.py *.mod vicNl -vic_classic -vic_image +vic_classic.exe +vic_image.exe liblnd.a _vic.py @@ -35,5 +35,6 @@ TAGS *egg-info* # Python stuff +__pycache__ .ipynb_checkpoints .eggs diff --git a/.travis.yml b/.travis.yml index 53c1ccc06..59d8a85e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,8 @@ matrix: addons: apt_packages: - libnetcdf-dev + - netcdf-bin + - netcdf-doc - gfortran - valgrind # open-mpi is built from source in image.travis @@ -23,6 +25,8 @@ matrix: addons: apt_packages: - libnetcdf-dev + - netcdf-bin + - netcdf-doc - gfortran # open-mpi is built from source in cesm.travis # Classic Driver diff --git a/ci/image.travis b/ci/image.travis index afca7fb22..cac9c9ffc 100644 --- a/ci/image.travis +++ b/ci/image.travis @@ -34,11 +34,13 @@ function vic_before_install { brew install homebrew/versions/gcc49 brew reinstall open-mpi --build-from-source fi - export TRAVIS_NETCDFPATH=/usr/local - export TRAVIS_MPIPATH=/usr/local + export TRAVIS_MPIPATH=/usr/local + export NC_LIBS=$(/usr/local/bin/nc-config --libs) + export NC_CFLAGS=$(/usr/local/bin/nc-config --cflags) else - export TRAVIS_NETCDFPATH=/usr export TRAVIS_MPIPATH="${HOME}/mpich" + export NC_LIBS=$(/usr/bin/nc-config --libs) + export NC_CFLAGS=$(/usr/bin/nc-config --cflags) # Install MPICH if [ ! -d ${TRAVIS_MPIPATH} ]; then @@ -46,11 +48,15 @@ function vic_before_install { else echo "MPICH installed..." fi - find ${TRAVIS_MPIPATH} -name mpiexec - find ${TRAVIS_MPIPATH} -name mpicc fi - export PATH=$TRAVIS_MPIPATH/bin:$PATH + export PATH=${TRAVIS_MPIPATH}/bin:${PATH} + find ${TRAVIS_MPIPATH} -name mpiexec mpiexec --version + find ${TRAVIS_MPIPATH} -name mpicc + export MPICC="${TRAVIS_MPIPATH}/bin/mpicc" + $MPICC --version + echo "NETCDF LIB FLAGS ------> ${NC_LIBS}" + echo "NETCDF C FLAGS --------> ${NC_CFLAGS}" } function vic_install { diff --git a/vic/drivers/image/Makefile b/vic/drivers/image/Makefile index 1984ff666..b80455cd4 100644 --- a/vic/drivers/image/Makefile +++ b/vic/drivers/image/Makefile @@ -38,43 +38,23 @@ SHAREDIMAGEPATH = ../shared_image # VIC RUN PATH VICPATH = ../../vic_run -UNAME_S := $(shell uname -s) - -# NETCDF include .. change the path depending on travis or other location -ifeq (true, ${TRAVIS}) -NETCDFPATH = ${TRAVIS_NETCDFPATH} -else ifeq (hydro-c1, $(shell hostname)) -NETCDFPATH = /usr/local/netcdf-4.3.0+gcc-4.7.2 -else ifeq ($(UNAME_S), Linux) -NETCDFPATH = /usr -else -NETCDFPATH = /opt/local +ifndef NC_LIBS +NC_LIBS = $(shell nc-config --libs) endif +$(info $$NC_LIBS is [${NC_LIBS}]) -# MPI include .. change the path depending on travis or other location -ifeq (true, ${TRAVIS}) -MPIPATH = ${TRAVIS_MPIPATH} -else ifeq (hydro-c1, $(shell hostname)) -MPIPATH = /usr/local/netcdf-4.3.0+gcc-4.7.2 -else ifeq ($(UNAME_S), Linux) -MPIPATH = /usr -else -MPIPATH = /opt/local +ifndef NC_CFLAGS +NC_CFLAGS = $(shell nc-config --cflags) endif +$(info $$NC_CFLAGS is [${NC_CFLAGS}]) -# Set SHELL = your shell here -SHELL = /bin/bash - -# Set CC = your compiler here -ifeq (true, ${TRAVIS}) -CC = ${MPIPATH}/bin/mpicc -else ifeq ($(UNAME_S), Linux) -CC = ${MPIPATH}/bin/mpicc -else -CC = mpicc +ifndef MPICC +MPICC = mpicc endif +$(info $$MPICC is [${MPICC}]) GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags) +UNAME_S := $(shell uname -s) HOSTNAME := $(shell uname -n) # Set the log level @@ -91,11 +71,10 @@ LOG_LVL = 5 INCLUDES = -I ${DRIVERPATH}/include \ -I ${VICPATH}/include \ -I ${SHAREDPATH}/include \ - -I ${SHAREDIMAGEPATH}/include \ - -I ${NETCDFPATH}/include \ + -I ${SHAREDIMAGEPATH}/include # Uncomment to include debugging information -CFLAGS = ${INCLUDES} -ggdb -O0 -Wall -Wextra -std=c99 \ +CFLAGS = ${INCLUDES} ${NC_CFLAGS} -ggdb -O0 -Wall -Wextra -std=c99 \ -DLOG_LVL=$(LOG_LVL) \ -DGIT_VERSION=\"$(GIT_VERSION)\" \ -DUSERNAME=\"$(USER)\" \ @@ -106,7 +85,7 @@ ifeq (true, ${TRAVIS}) CFLAGS += -rdynamic -Wl,-export-dynamic endif -LIBRARY = -lm -L${NETCDFPATH}/lib -lnetcdf +LIBRARY = -lm ${NC_LIBS} COMPEXE = vic_image EXT = .exe @@ -148,7 +127,7 @@ clean:: \rm -rf ${COMPEXE}${EXT} ${COMPEXE}${EXT}.dSYM model: $(OBJS) - $(CC) -o ${COMPEXE}${EXT} $(OBJS) $(CFLAGS) $(LIBRARY) + $(MPICC) -o ${COMPEXE}${EXT} $(OBJS) $(CFLAGS) $(LIBRARY) # ------------------------------------------------------------- # tags @@ -166,7 +145,7 @@ clean:: # ------------------------------------------------------------- depend: .depend .depend: $(SRCS) $(HDRS) - $(CC) $(CFLAGS) -M $(SRCS) > $@ + $(MPICC) $(CFLAGS) -M $(SRCS) > $@ clean:: \rm -f .depend diff --git a/vic/drivers/shared_all/include/vic_version.h b/vic/drivers/shared_all/include/vic_version.h index d16be23af..3f1b191ae 100644 --- a/vic/drivers/shared_all/include/vic_version.h +++ b/vic/drivers/shared_all/include/vic_version.h @@ -62,7 +62,7 @@ #elif defined(__ICC) || defined(__INTEL_COMPILER) /* Intel ICC/ICPC. ------------------------------------------ */ # define COMPILER "icc" -# define COMPILER_VERSION __version__ +# define COMPILER_VERSION __VERSION__ #elif defined(__GNUC__) || defined(__GNUG__) /* GNU GCC/G++. --------------------------------------------- */ From 53105161631b960c17819eeb19487aee4369a88d Mon Sep 17 00:00:00 2001 From: yixinmao Date: Thu, 28 Jul 2016 11:33:01 -0700 Subject: [PATCH 14/33] Add MPI test (#567) * Add mpi multiprocessing test - test whether the flux and state results using different number of processors are exactly identical for image driver * Add instruction on running VIC image driver using multiple processors to the documentation * Remove state output in mpi test - for debugging purpose * Add back outputing state file in mpi test * Add debug lines in VIC source code to debug failing MPI when writing state file * fixed bug of missing statesec in mpi global parameter file * Remove some debugging lines in the VIC code for detecting MPI bug (bug fixed) --- docs/Documentation/Drivers/Image/RunVIC.md | 6 + tests/run_tests.py | 61 ++++++- tests/system/global.image.STEHE.mpi.txt | 71 ++++++++ tests/system/system_tests.cfg | 11 ++ tests/test_image_driver.py | 161 ++++++++++++++++++ vic/drivers/image/src/vic_image.c | 13 +- .../shared_all/src/print_library_shared.c | 1 + .../shared_image/src/vic_mpi_support.c | 6 +- 8 files changed, 322 insertions(+), 8 deletions(-) create mode 100644 tests/system/global.image.STEHE.mpi.txt diff --git a/docs/Documentation/Drivers/Image/RunVIC.md b/docs/Documentation/Drivers/Image/RunVIC.md index 05b2b9b44..65aa139ec 100644 --- a/docs/Documentation/Drivers/Image/RunVIC.md +++ b/docs/Documentation/Drivers/Image/RunVIC.md @@ -41,6 +41,12 @@ At the command prompt, type: where `global_parameter_filename` = name of the global parameter file corresponding to your project. +To run VIC image driver using multiple processor, type the following instead: + +`mpiexec -np n_proc vic_image.exe -g global_parameter_filename` + +where `n_proc` = number of processors to be used + ## Other Command Line Options VIC has a few other command line options: diff --git a/tests/run_tests.py b/tests/run_tests.py index cdda2d4aa..6bcc99d27 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -24,7 +24,9 @@ find_global_param_value, check_multistream_classic) from test_image_driver import (test_image_driver_no_output_file_nans, - check_multistream_image) + check_multistream_image, + setup_subdirs_and_fill_in_global_param_mpi_test, + check_mpi_fluxes, check_mpi_states) from test_restart import (prepare_restart_run_periods, setup_subdirs_and_fill_in_global_param_restart_test, check_exact_restart_fluxes, @@ -338,6 +340,13 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): run_periods = prepare_restart_run_periods( test_dict['restart'], dirs['state'], statesec) + # If mpi test, prepare a list of number of processors to be run + elif 'mpi' in test_dict['check']: + if not isinstance(test_dict['mpi']['n_proc'], list): + print('Error: need at least two values in n_proc to run' + 'mpi test!') + raise + list_n_proc = test_dict['mpi']['n_proc'] # create template string s = string.Template(global_param) @@ -351,7 +360,15 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): setup_subdirs_and_fill_in_global_param_restart_test( s, run_periods, driver, dirs['results'], dirs['state'], test_data_dir) - # else, single run + # --- if mpi test, multiple runs --- # + elif 'mpi' in test_dict['check']: + # Set up subdirectories and output directories in global file for + # multiprocessor testing + list_global_param = \ + setup_subdirs_and_fill_in_global_param_mpi_test( + s, list_n_proc, dirs['results'], dirs['state'], + test_data_dir) + # --- else, single run --- # else: global_param = s.safe_substitute(test_data_dir=test_data_dir, result_dir=dirs['results'], @@ -368,14 +385,15 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): if 'STATE_FORMAT' in replacements: state_format = replacements['STATE_FORMAT'] # --- replace global options --- # - if 'exact_restart' in test_dict['check']: + if 'exact_restart' in test_dict['check'] or\ + 'mpi' in test_dict['check']: # if multiple runs for j, gp in enumerate(list_global_param): # save a copy of replacements for the next global file replacements_cp = replacements.copy() # replace global options for this global file list_global_param[j] = replace_global_values(gp, replacements) replacements = replacements_cp - else: + else: # if single run global_param = replace_global_values(global_param, replacements) # write global parameter file @@ -392,6 +410,17 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): with open(test_global_file, mode='w') as f: for line in gp: f.write(line) + elif 'mpi' in test_dict['check']: + list_test_global_file = [] + for j, gp in enumerate(list_global_param): + test_global_file = os.path.join( + dirs['test'], + '{}_globalparam_processors_{}.txt'.format( + testname, list_n_proc[j])) + list_test_global_file.append(test_global_file) + with open(test_global_file, mode='w') as f: + for line in gp: + f.write(line) else: test_global_file = os.path.join( dirs['test'], @@ -413,7 +442,23 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): if 'exact_restart' in test_dict['check']: for j, test_global_file in enumerate(list_test_global_file): returncode = vic_exe.run(test_global_file, - logdir=dirs['logs']) + logdir=dirs['logs'], + **run_kwargs) + # Check return code + check_returncode(vic_exe, + test_dict.pop('expected_retval', 0)) + if 'mpi' in test_dict['check']: + for j, test_global_file in enumerate(list_test_global_file): + # Overwrite mpi_proc in option kwargs + n_proc = list_n_proc[j] + if n_proc == 1: + run_kwargs['mpi_proc'] = None + else: + run_kwargs['mpi_proc'] = list_n_proc[j] + # Run VIC + returncode = vic_exe.run(test_global_file, + logdir=dirs['logs'], + **run_kwargs) # Check return code check_returncode(vic_exe, test_dict.pop('expected_retval', 0)) @@ -460,6 +505,7 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): check_exact_restart_states(dirs['state'], driver, run_periods, statesec) + # check for multistream output if 'multistream' in test_dict['check']: fnames = glob.glob(os.path.join(dirs['results'], '*')) if driver == 'classic': @@ -468,6 +514,11 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): warnings.warn('Skipping multistream image driver test') # TODO: check_multistream_image(fnames) + # check for mpi multiprocessor results + if 'mpi' in test_dict['check']: + check_mpi_fluxes(dirs['results'], list_n_proc) + check_mpi_states(dirs['state'], list_n_proc) + # if we got this far, the test passed. test_passed = True diff --git a/tests/system/global.image.STEHE.mpi.txt b/tests/system/global.image.STEHE.mpi.txt new file mode 100644 index 000000000..f247f6d16 --- /dev/null +++ b/tests/system/global.image.STEHE.mpi.txt @@ -0,0 +1,71 @@ +NODES 3 +MODEL_STEPS_PER_DAY 24 +SNOW_STEPS_PER_DAY 24 +RUNOFF_STEPS_PER_DAY 24 +STARTYEAR 1949 +STARTMONTH 1 +STARTDAY 1 +ENDYEAR 1949 +ENDMONTH 1 +ENDDAY 10 +CALENDAR PROLEPTIC_GREGORIAN +FULL_ENERGY FALSE +FROZEN_SOIL FALSE + +DOMAIN $test_data_dir/image/Stehekin/parameters/domain.stehekin.20151028.nc +DOMAIN_TYPE LAT lat +DOMAIN_TYPE LON lon +DOMAIN_TYPE MASK mask +DOMAIN_TYPE AREA area +DOMAIN_TYPE FRAC frac +DOMAIN_TYPE YDIM lat +DOMAIN_TYPE XDIM lon + +#INIT_STATE +STATENAME $state_dir/states +STATEYEAR 1949 +STATEMONTH 1 +STATEDAY 10 +STATESEC 82800 + +FORCING1 $test_data_dir/image/Stehekin/forcings/Stehekin_image_test.forcings_10days. +FORCE_TYPE AIR_TEMP tas +FORCE_TYPE PREC prcp +FORCE_TYPE PRESSURE pres +FORCE_TYPE SWDOWN dswrf +FORCE_TYPE LWDOWN dlwrf +FORCE_TYPE VP shum +FORCE_TYPE WIND wind +WIND_H 10.0 + +PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +BASEFLOW ARNO +JULY_TAVG_SUPPLIED FALSE +ORGANIC_FRACT FALSE +LAI_SRC FROM_VEGPARAM +SNOW_BAND TRUE + +RESULT_DIR $result_dir + +OUTFILE fluxes +AGGFREQ NHOURS 1 +OUTVAR OUT_PREC +OUTVAR OUT_RAINF +OUTVAR OUT_SNOWF +OUTVAR OUT_AIR_TEMP +OUTVAR OUT_SWDOWN +OUTVAR OUT_LWDOWN +OUTVAR OUT_PRESSURE +OUTVAR OUT_WIND +OUTVAR OUT_DENSITY +OUTVAR OUT_REL_HUMID +OUTVAR OUT_QAIR +OUTVAR OUT_VP +OUTVAR OUT_VPD +OUTVAR OUT_RUNOFF +OUTVAR OUT_BASEFLOW +OUTVAR OUT_EVAP +OUTVAR OUT_SWE +OUTVAR OUT_SOIL_MOIST +OUTVAR OUT_ALBEDO +OUTVAR OUT_SOIL_TEMP diff --git a/tests/system/system_tests.cfg b/tests/system/system_tests.cfg index 8c295aacc..5927c81cb 100644 --- a/tests/system/system_tests.cfg +++ b/tests/system/system_tests.cfg @@ -225,3 +225,14 @@ driver = image global_parameter_file = global.image.STEHE.allhistvars.txt expected_retval = 0 check = nonans + +[System-mpi_image_check_identical_results] +test_description = check that multi-processor runs produce identical results - image driver +driver = image +global_parameter_file = global.image.STEHE.mpi.txt +expected_retval = 0 +check = mpi +[[mpi]] +# A list of number of processors to run and compare (need at least a list of two numbers) +n_proc = 1,4 + diff --git a/tests/test_image_driver.py b/tests/test_image_driver.py index ef0f7380c..13b04c6a6 100644 --- a/tests/test_image_driver.py +++ b/tests/test_image_driver.py @@ -7,6 +7,7 @@ import pandas as pd import numpy as np import numpy.testing as npt +import glob def test_image_driver_no_output_file_nans(fnames, domain_file): @@ -133,3 +134,163 @@ def reindex_xr_obj_timedim(obj, freq): print('actual=%s\nexpected=%s' % (actual, expected)) print(np.abs(actual-expected).max()) raise e + + +def setup_subdirs_and_fill_in_global_param_mpi_test( + s, list_n_proc, result_basedir, state_basedir, test_data_dir): + ''' Fill in global parameter output directories for multiple runs for mpi + testing, image driver + + Parameters + ---------- + s: + Template of the global param file to be filled in + list_n_proc: + A list of number of processors to run and compare + result_basedir: + Base directory of output fluxes results; runs with different number of + processors are output to subdirectories under the base directory + state_basedir: + Base directory of output state results; runs with different number of + processors are output to subdirectories under the base directory + test_data_dir: + Base directory of test data + + Returns + ---------- + list_global_param: + A list of global parameter strings to be run with parameters filled in + + Require + ---------- + os + ''' + + list_global_param = [] + for j, n_proc in enumerate(list_n_proc): + # Set up subdirectories for results and states + result_dir = os.path.join( + result_basedir, + 'processors_{}'.format(n_proc)) + state_dir = os.path.join( + state_basedir, + 'processors_{}'.format(n_proc)) + os.makedirs(result_dir, exist_ok=True) + os.makedirs(state_dir, exist_ok=True) + + # Fill in global parameter options + list_global_param.append(s.safe_substitute( + test_data_dir=test_data_dir, + result_dir=result_dir, + state_dir=state_dir)) + + return(list_global_param) + + +def check_mpi_fluxes(result_basedir, list_n_proc): + ''' Check whether all the fluxes are the same with different number of + processors, image driver + + Parameters + ---------- + result_basedir: + Base directory of output fluxes results; runs with different number of + processors are output to subdirectories under the base directory + list_n_proc: + A list of number of processors to run and compare + + Require + ---------- + os + glob + numpy + ''' + + # Read the first run - as base + n_proc = list_n_proc[0] + result_dir = os.path.join( + result_basedir, + 'processors_{}'.format(n_proc)) + if len(glob.glob(os.path.join(result_dir, '*.nc'))) > 1: + print( + 'Warning: more than one netCDF file found under directory {}'. + format(result_dir)) + fname = glob.glob(os.path.join(result_dir, '*.nc'))[0] + ds_first_run = xr.open_dataset(fname) + + # Loop over all rest runs and compare fluxes with the base run + for i, n_proc in enumerate(list_n_proc): + # Skip the first run + if i == 0: + continue + # Read flux results for this run + result_dir = os.path.join( + result_basedir, + 'processors_{}'.format(n_proc)) + if len(glob.glob(os.path.join(result_dir, '*.nc'))) > 1: + print( + 'Warning: more than one netCDF file found under directory {}'. + format(result_dir)) + fname = glob.glob(os.path.join(result_dir, '*.nc'))[0] + ds_current_run = xr.open_dataset(fname) + # Compare current run with base run + for var in ds_first_run.data_vars: + npt.assert_array_equal( + ds_current_run[var].values, + ds_first_run[var].values, + err_msg='Fluxes are not an exact match') + + +def check_mpi_states(state_basedir, list_n_proc): + ''' Check whether all the output states are the same with different number + of processors, image driver + + Parameters + ---------- + state_basedir: + Base directory of output states; runs with different number of + processors are output to subdirectories under the base directory + list_n_proc: + A list of number of processors to run and compare + + Require + ---------- + os + glob + numpy + ''' + + # Read the first run - as base + n_proc = list_n_proc[0] + state_dir = os.path.join( + state_basedir, + 'processors_{}'.format(n_proc)) + if len(glob.glob(os.path.join(state_dir, '*.nc'))) > 1: + print( + 'Warning: more than one netCDF file found under directory {}'. + format(state_dir)) + fname = glob.glob(os.path.join(state_dir, '*.nc'))[0] + ds_first_run = xr.open_dataset(fname) + + # Loop over all rest runs and compare fluxes with the base run + for i, n_proc in enumerate(list_n_proc): + # Skip the first run + if i == 0: + continue + # Read output states for this run + state_dir = os.path.join( + state_basedir, + 'processors_{}'.format(n_proc)) + if len(glob.glob(os.path.join(state_dir, '*.nc'))) > 1: + print( + 'Warning: more than one netCDF file found under directory {}'. + format(result_dir)) + fname = glob.glob(os.path.join(state_dir, '*.nc'))[0] + ds_current_run = xr.open_dataset(fname) + # Compare current run with base run + for var in ds_first_run.data_vars: + npt.assert_array_equal( + ds_current_run[var].values, + ds_first_run[var].values, + err_msg='States are not an exact match') + diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index 75be0ec73..163839095 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -119,6 +119,11 @@ main(int argc, // initialize output structures vic_init_output(&(dmy[0])); + // Initialization is complete, print settings + log_info("Initialization is complete, print global param and options structures"); + print_global_param(&global_param); + print_option(&options); + // stop init timer timer_stop(&(global_timers[TIMER_VIC_INIT])); // start vic run timer @@ -137,6 +142,7 @@ main(int argc, // Write state file if (check_save_state_flag(current)) { + debug("writing state file for timestep %zu", current); vic_store(&(dmy[current]), state_filename); debug("finished storing state file: %s", state_filename) } @@ -160,8 +166,11 @@ main(int argc, timer_stop(&(global_timers[TIMER_VIC_FINAL])); // stop vic all timer timer_stop(&(global_timers[TIMER_VIC_ALL])); - // write timing info - write_vic_timing_table(global_timers, VIC_DRIVER); + + if (mpi_rank == VIC_MPI_ROOT) { + // write timing info + write_vic_timing_table(global_timers, VIC_DRIVER); + } return EXIT_SUCCESS; } diff --git a/vic/drivers/shared_all/src/print_library_shared.c b/vic/drivers/shared_all/src/print_library_shared.c index b725365f8..a7dd131cf 100644 --- a/vic/drivers/shared_all/src/print_library_shared.c +++ b/vic/drivers/shared_all/src/print_library_shared.c @@ -282,6 +282,7 @@ print_global_param(global_param_struct *gp) fprintf(LOG_DEST, "\tstateday : %hu\n", gp->stateday); fprintf(LOG_DEST, "\tstatemonth : %hu\n", gp->statemonth); fprintf(LOG_DEST, "\tstateyear : %hu\n", gp->stateyear); + fprintf(LOG_DEST, "\tstatesec : %u\n", gp->statesec); } /****************************************************************************** diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index 4636975f1..0f73a5e84 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -103,7 +103,7 @@ create_MPI_global_struct_type(MPI_Datatype *mpi_type) MPI_Datatype *mpi_types; // nitems has to equal the number of elements in global_param_struct - nitems = 31; + nitems = 32; blocklengths = malloc(nitems * sizeof(*blocklengths)); check_alloc_status(blocklengths, "Memory allocation error."); @@ -232,6 +232,10 @@ create_MPI_global_struct_type(MPI_Datatype *mpi_type) offsets[i] = offsetof(global_param_struct, statemonth); mpi_types[i++] = MPI_UNSIGNED_SHORT; + // unsigned int statesec; + offsets[i] = offsetof(global_param_struct, statesec); + mpi_types[i++] = MPI_UNSIGNED; + // unsigned short int stateyear; offsets[i] = offsetof(global_param_struct, stateyear); mpi_types[i++] = MPI_UNSIGNED_SHORT; From 1fb71cf6fc68add2f4b1ff3446c0eb6ae650747b Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 28 Jul 2016 12:13:15 -0700 Subject: [PATCH 15/33] VIC 5 performance profiling (#560) * add profiling tests and also print timing table from end of std out when profiling -- usefull when understanding the runtime along side the call graph --- .gitignore | 6 + ci/requirements.yml | 2 + tests/profiling/README.md | 4 + tests/profiling/run_gprof.bash | 58 +++++++++ tests/run_profiling.py | 221 +++++++++++++++++++++++++++++++++ 5 files changed, 291 insertions(+) create mode 100644 tests/profiling/README.md create mode 100755 tests/profiling/run_gprof.bash create mode 100755 tests/run_profiling.py diff --git a/.gitignore b/.gitignore index 674f2d010..5c0ef4d1f 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,12 @@ vic_classic.exe vic_image.exe liblnd.a _vic.py +vic_timing_*txt +massif.out.* +vic_call_graph_* + +vic_call_graph* +gmon.out .DS_Store TAGS diff --git a/ci/requirements.yml b/ci/requirements.yml index 6e97212fb..cbc696634 100644 --- a/ci/requirements.yml +++ b/ci/requirements.yml @@ -10,8 +10,10 @@ dependencies: - configobj - xarray - bottleneck + - psutil - pip: - git+https://github.com/UW-Hydro/tonic.git - engarde - pytest-faulthandler - pytest-xdist + - gprof2dot diff --git a/tests/profiling/README.md b/tests/profiling/README.md new file mode 100644 index 000000000..ffa974bba --- /dev/null +++ b/tests/profiling/README.md @@ -0,0 +1,4 @@ +VIC Profiling Tests +======= + +These tests quantify the performance of VIC in terms of CPU/wall time and memory usage. diff --git a/tests/profiling/run_gprof.bash b/tests/profiling/run_gprof.bash new file mode 100755 index 000000000..a813acd37 --- /dev/null +++ b/tests/profiling/run_gprof.bash @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -e +# set -x + +# A POSIX variable +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Initialize our own variables: +vic_exe="" +vic_global="" + +function usage { + echo "Usage: `basename $0` -e vic_executable -g vic_global -h for help"; +} + + +while getopts "h?e::g::" opt; do + case "$opt" in + h|\?) + usage + exit 0 + ;; + e) vic_exe=$OPTARG ;; + g) vic_global=$OPTARG ;; + esac +done + +shift $((OPTIND-1)) + +[ "$1" = "--" ] && shift + +GIT_VERSION=$(git describe --abbrev=4 --dirty --always --tags) + +echo "----------------------- START VIC GPROF PROFILING -----------------------" +echo "" +echo "Date : $(date)" +echo "Machine : $HOSTNAME" +echo "User : $USER" +echo "VIC Test Git Version : $GIT_VERSION" +echo "VIC Executable : $vic_exe" +echo "VIC Global Parameter File : $vic_global" +echo "" + +echo "VIC Executable Version Info" +echo "---------------------------" +$vic_exe -v +echo "" + +$vic_exe -g $vic_global 2>&1 | tail -n 55 + +now=`date +"%y%m%d"` +gprof $vic_exe | gprof2dot | dot -Tpng -o vic_call_graph_$now.png + +echo "" +echo "------------------------ END VIC GPROF PROFILING ------------------------" +exit 0 + +# End of file diff --git a/tests/run_profiling.py b/tests/run_profiling.py new file mode 100755 index 000000000..796fe3be9 --- /dev/null +++ b/tests/run_profiling.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python +'''VIC testing command line interface''' + +from __future__ import print_function +import os +import argparse +from collections import namedtuple +import psutil +import string +import subprocess +from subprocess import check_call +import datetime +import getpass +import socket +import time + +import numpy as np + +from tonic.models.vic.vic import VIC + +host_config = namedtuple('host_config', + ('max_cores', 'template', 'submit', 'mpiexec')) + +table_header = '''----------------- START VIC SCALING PROFILE ----------------- + +Date : $date +Machine : $hostname +User : $user +VIC Test Git Version : $git_version +VIC Executable : $vic_exe +VIC Global Parameter File : $vic_global +Test Maximum MPI Cores : $max_cores + +VIC Executable Version Info +--------------------------- +$vic_version +Cores | Time (Seconds) +---------------------- +''' + + +hosts = { + 'local': host_config(max_cores=psutil.cpu_count(), submit=None, template=None, + mpiexec=os.getenv('MPIEXEC', 'mpiexec')), + 'hydra': host_config(max_cores=64, submit='qsub', mpiexec='mpiexec', + template='''#!/bin/bash +# +#$ -N VIC_scaling_test_$np +#$ -cwd +#$ -j y +#$ -S /bin/bash +#$ -m be +#$ -pe orte $np + +# Qsub template for UW's Hydra Cluster +# Scheduler: SGE +# Valid values for np 1-64 +if [ "$np" -gt "64" ] + echo "$np exceeds maximum number of processes on Hydra" + exit 1 +fi + +START=$(date +%s) +mpiexec -np $np $vic_exe -g $vic_global +END=$(date +%s) +DIFF=$(echo "$END - $START" | bc) +printf "%5s | %f" $np $DIFF >> $timing_table_file'''), + } + +OUTPUT_WIDTH = 100 + +description = ''' + VIC Test Suite +------------------------------------------------------------------------------- +This is the VIC Profiling Test Suite. There are 2 main test types: + + 1. Gprof Profiling: This test will generate a profiling call graph using + gprof. This test requires building your VIC executable with the flags `-pg`. + 2. Scaling: This test will generate a MPI scaling timing table. +------------------------------------------------------------------------------- +''' + +epilog = ''' +------------------------------------------------------------------------------- +For questions about the development or use of VIC or use of this test module, +please email the VIC users list serve at vic_users@u.washington.edu. +------------------------------------------------------------------------------- +''' + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass + + +def main(): + ''' ''' + # dates and times + starttime = datetime.datetime.now() + ymd = starttime.strftime('%Y%m%d') + + # parse command line options + parser = argparse.ArgumentParser(description=description, epilog=epilog, + formatter_class=CustomFormatter) + + parser.add_argument('vic_exe', type=str, + help='VIC executable to test') + parser.add_argument('--kind', type=str, + help='Specify which type of test should be run', + choices=['scaling', 'profile'], + default='scaling') + parser.add_argument('--host', type=str, + help='Host machine to run test on, if not specified, ' + 'test will be run locally', + choices=list(hosts.keys()), + default='local') + parser.add_argument('--global_param', '-g', type=str, + help='global parameter file to test') + parser.add_argument('--timing', '-t', type=str, + default='vic_timing_{}.txt'.format(ymd), + help='path to timing file') + parser.add_argument('--clean', action='store_true', help='Clean up run files') + parser.add_argument('--test', action='store_true', + help='Test the setup but do not run VIC') + + args = parser.parse_args() + + if args.global_param is None: + raise ValueError('Global Parameter option is required') + + if args.kind == 'scaling': + run_scaling(args) + elif args.kind == 'profile': + run_profiling(args) + else: + raise ValueError('Unknown test kind %s' % args.kind) + + +def run_profiling(args): + '''wrapper function for profiling tests''' + cmd = './profiling/run_gprof.bash -e {vic_exe} -g {vic_global}'.format( + vic_exe=args.vic_exe, vic_global=args.global_param) + check_call(cmd, shell=True) + + +def run_scaling(args): + '''wrapper function for scaling tests''' + config = hosts[args.host] + vic_exe = VIC(args.vic_exe) + + # write timing file header + header = string.Template(table_header) + header_kwargs = get_header_info(args.vic_exe, args.global_param, + config.max_cores) + header = header.safe_substitute(**header_kwargs) + with open(args.timing, 'w') as f: + f.write(header) + + for n in log2_range(config.max_cores).astype(np.int): + if config.template: + # run on a cluster of some kind + # start by printing the template + print('-'.ljust(OUTPUT_WIDTH, '-')) + print('{host} template'.format(host=args.host).center(OUTPUT_WIDTH)) + print('-'.ljust(OUTPUT_WIDTH, '-')) + print(config.template) + print('-'.ljust(OUTPUT_WIDTH, '-')) + template = string.Template(config.template) + + run_string = template.safe_substitute(np=n, vic_exe=args.vic_exe, + vic_global=args.global_param, + timing_table_file=args.timing) + run_file = 'vic_{host}_{n}.sh'.format(host=args.host, n=n) + with open(run_file, 'w') as f: + f.write(run_string) + + cmd = '{submit} {run_file}'.format(submit=config.submit, + run_file=run_file) + print(cmd) + if not args.test: + check_call(cmd, shell=True) + + if args.clean: + os.remove(run_file) + else: + # run locally + print('Running {} with {} processors'.format(args.vic_exe, n)) + if not args.test: + start = time.time() + vic_exe.run(args.global_param, mpi_proc=int(n)) + end = time.time() + diff = end - start + with open(args.timing, 'a') as f: + f.write('%5s | %.2f\n' % (n, diff)) + + print('See %s for scaling table' % args.timing) + + +def log2_range(m): + '''make an array of integers that increase by 2^n with maximum value of m''' + n = int(np.floor(np.log2(m))) + 1 + return np.exp2(np.arange(n)).astype(np.int) + + +def get_header_info(vic_exe, vic_global, max_cores): + '''get info for timing table headers''' + header_kwargs = {} + header_kwargs['date'] = datetime.datetime.now() + header_kwargs['hostname'] = socket.gethostname() + header_kwargs['user'] = getpass.getuser() + header_kwargs['git_version'] = subprocess.check_output( + ['git', 'describe', '--abbrev=4', '--dirty', '--always', '--tags']).decode() + header_kwargs['vic_exe'] = vic_exe + header_kwargs['vic_global'] = vic_global + header_kwargs['max_cores'] = max_cores + header_kwargs['vic_version'] = subprocess.check_output([vic_exe, '-v']).decode() + return header_kwargs + + +if __name__ == '__main__': + main() From 3e66adbde2eac80ad7aca4c958d0a2253c35f495 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 28 Jul 2016 15:32:08 -0700 Subject: [PATCH 16/33] cleanup compiler warnings for intel builds --- docs/Documentation/Drivers/Image/RunVIC.md | 15 +++++++++++---- .../include/vic_driver_shared_image.h | 2 +- .../include/{vic_nc_log.h => vic_image_log.h} | 8 ++------ vic/drivers/shared_image/include/vic_mpi.h | 1 + vic/drivers/shared_image/src/vic_mpi_support.c | 5 +---- 5 files changed, 16 insertions(+), 15 deletions(-) rename vic/drivers/shared_image/include/{vic_nc_log.h => vic_image_log.h} (96%) diff --git a/docs/Documentation/Drivers/Image/RunVIC.md b/docs/Documentation/Drivers/Image/RunVIC.md index 65aa139ec..e53076500 100644 --- a/docs/Documentation/Drivers/Image/RunVIC.md +++ b/docs/Documentation/Drivers/Image/RunVIC.md @@ -22,9 +22,16 @@ The Image Driver's has three dependencies: ## Compiling In most cases, you will need to edit the `NETCDF_PATH` and `MPI_PATH` variables in the `Makefile`. -If you want to use a compiler other than `gcc`, either edit the Makefile or set the `CC` environment variable, e.g. +If you want to use a compiler other than `mpicc`, either edit the Makefile or set the `MPICC` environment variable, e.g. - export CC=icc + MPICC=/path/to/mpi_c_compiler + +The flags and libraries required to compile VIC with netCDF are automatically determined in the `Makefile`. They can be overwritten by setting the following two environment variables. These variables can be determined by running `nc-config --all`. + + NC_LIBS="-L/path/to/libs ..." + NC_CFLAGS="-I/path/to/includes -your_c_flags ..." + +In some versions of the MPI library (e.g. OPEN-MPI with Intel), you may also need to set the environment variable `MX_RCACHE=2` prior to compiling. - Change directory, `cd`, to the "Image Driver" source code directory and type `make` @@ -37,13 +44,13 @@ If you want to use a compiler other than `gcc`, either edit the Makefile or set At the command prompt, type: -`vic_image.exe -g global_parameter_filename` +`vic_image.exe -g global_parameter_filename.txt` where `global_parameter_filename` = name of the global parameter file corresponding to your project. To run VIC image driver using multiple processor, type the following instead: -`mpiexec -np n_proc vic_image.exe -g global_parameter_filename` +`mpiexec -np n_proc vic_image.exe -g global_parameter_filename.txt` where `n_proc` = number of processors to be used diff --git a/vic/drivers/shared_image/include/vic_driver_shared_image.h b/vic/drivers/shared_image/include/vic_driver_shared_image.h index f8861f2b6..5655aabda 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -28,7 +28,7 @@ #define VIC_DRIVER_SHARED_IMAGE_H #include -#include +#include #include #include diff --git a/vic/drivers/shared_image/include/vic_nc_log.h b/vic/drivers/shared_image/include/vic_image_log.h similarity index 96% rename from vic/drivers/shared_image/include/vic_nc_log.h rename to vic/drivers/shared_image/include/vic_image_log.h index 849b60700..151f2c191 100644 --- a/vic/drivers/shared_image/include/vic_nc_log.h +++ b/vic/drivers/shared_image/include/vic_image_log.h @@ -38,16 +38,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#ifndef __vic_nc_log_h__ -#define __vic_nc_log_h__ +#ifndef __vic_image_log_h__ +#define __vic_image_log_h__ #include #include -void print_mpi_error_str(int error_code); - -void print_mpi_error_str(int error_code); - // Macros for logging #define clean_ncerrno(e) (e == NC_NOERR ? "None" : nc_strerror(e)) diff --git a/vic/drivers/shared_image/include/vic_mpi.h b/vic/drivers/shared_image/include/vic_mpi.h index 95c849059..c72d5131e 100644 --- a/vic/drivers/shared_image/include/vic_mpi.h +++ b/vic/drivers/shared_image/include/vic_mpi.h @@ -61,5 +61,6 @@ void mpi_map_decomp_domain(size_t ncells, size_t mpi_size, int **mpi_map_local_array_sizes, int **mpi_map_global_array_offsets, size_t **mpi_map_mapping_array); +void print_mpi_error_str(int error_code); #endif diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index 0f73a5e84..bc65c8184 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -66,10 +66,7 @@ initialize_mpi(void) check_mpi_status(status, "MPI Error"); // set mpi error handling - MPI_Errhandler_set(MPI_COMM_VIC, MPI_ERRORS_RETURN); - - // set mpi error handling - MPI_Errhandler_set(MPI_COMM_VIC, MPI_ERRORS_RETURN); + MPI_Comm_set_errhandler(MPI_COMM_VIC, MPI_ERRORS_RETURN); status = MPI_Comm_size(MPI_COMM_VIC, &mpi_size); check_mpi_status(status, "MPI Error"); From 37b434260cbfb18efd03fcbc307b46d5068ef489 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 28 Jul 2016 16:09:54 -0700 Subject: [PATCH 17/33] fix memcpy void pointer warnings --- vic/drivers/shared_image/src/vic_mpi_support.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index bc65c8184..127d5499b 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -1596,25 +1596,29 @@ map(size_t size, if (to_map == NULL && from_map == NULL) { for (i = 0; i < n; i++) { // type-agnostic version of to[i] = from[i]; - memcpy(to + i * size, from + i * size, size); + memcpy((void *)((char *)to + i * size), + (void *)((char *)from + i * size), size); } } if (to_map == NULL) { for (i = 0; i < n; i++) { // type-agnostic version of to[i] = from[from_map[i]]; - memcpy(to + i * size, from + from_map[i] * size, size); + memcpy((void *)((char *)to + i * size), + (void *)((char *)from + from_map[i] * size), size); } } else if (from_map == NULL) { for (i = 0; i < n; i++) { // type-agnostic version of to[to_map[i]] = from[i]; - memcpy(to + to_map[i] * size, from + i * size, size); + memcpy((void *)((char *)to + to_map[i] * size), + (void *)((char *)from + i * size), size); } } else { for (i = 0; i < n; i++) { // type-agnostic version of to[to_map[i]] = from[from_map[i]]; - memcpy(to + to_map[i] * size, from + from_map[i] * size, size); + memcpy((void *)((char *)to + to_map[i] * size), + (void *)((char *)from + from_map[i] * size), size); } } } From 6d7c59a96e9e0ec8e729dc88eb09168ebb5754c0 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 28 Jul 2016 16:31:49 -0700 Subject: [PATCH 18/33] initialize iter_soil_energy --- vic/vic_run/src/surface_fluxes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vic/vic_run/src/surface_fluxes.c b/vic/vic_run/src/surface_fluxes.c index de282c431..8354ba743 100644 --- a/vic/vic_run/src/surface_fluxes.c +++ b/vic/vic_run/src/surface_fluxes.c @@ -261,6 +261,7 @@ surface_fluxes(bool overstory, coverage = snow->coverage; snow_energy = (*energy); soil_energy = (*energy); + iter_soil_energy = (*energy); snow_veg_var = (*veg_var); soil_veg_var = (*veg_var); step_snow = (*snow); From df9ac2e9d3ae1c6368691f9e9add3bfd1c11793b Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Fri, 29 Jul 2016 10:16:13 -0700 Subject: [PATCH 19/33] update image driver run docs --- docs/Documentation/Drivers/Image/RunVIC.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Documentation/Drivers/Image/RunVIC.md b/docs/Documentation/Drivers/Image/RunVIC.md index e53076500..e877ea571 100644 --- a/docs/Documentation/Drivers/Image/RunVIC.md +++ b/docs/Documentation/Drivers/Image/RunVIC.md @@ -1,7 +1,7 @@ # Running the VIC Image Driver ## Dependencies: -The Image Driver's has three dependencies: +The Image Driver has three dependencies: 1. A C compiler. We routinely test VIC using the following compilers: From f07f249f2abd115872f5c42f4dc7d3635c5b62dd Mon Sep 17 00:00:00 2001 From: ymao Date: Fri, 29 Jul 2016 13:48:21 -0700 Subject: [PATCH 20/33] Fixed bug in calculating air density --- vic/drivers/shared_all/src/forcing_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vic/drivers/shared_all/src/forcing_utils.c b/vic/drivers/shared_all/src/forcing_utils.c index 34ad4faf5..bc209d9a8 100644 --- a/vic/drivers/shared_all/src/forcing_utils.c +++ b/vic/drivers/shared_all/src/forcing_utils.c @@ -94,7 +94,7 @@ air_density(double t, // rho = (p*1000)/(Rd * *t+CONST_TKFRZ) + (pv*1000)/(Rv * *t+CONST_TKFRZ); // approximation used in VIC - rho = 0.003486 * p / (275.0 + t); + rho = p / (CONST_RDAIR * (CONST_TKFRZ + t)); return rho; } From 49fcd7741a000761306b3ea10691abb573ee5f92 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Fri, 29 Jul 2016 14:01:17 -0700 Subject: [PATCH 21/33] mpich 3.2 went missing, now using 3.1b1 --- ci/cesm.travis | 2 -- ci/classic.travis | 2 -- ci/image.travis | 2 -- ci/vic_install_utils | 8 +++----- 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/ci/cesm.travis b/ci/cesm.travis index d45838e42..c14f8a1c1 100644 --- a/ci/cesm.travis +++ b/ci/cesm.travis @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -e - DRIVER_PATH="./vic/drivers/cesm/" DRIVER_LIB="${DRIVER_PATH}lndlib.a" diff --git a/ci/classic.travis b/ci/classic.travis index 300359712..cea2dd5be 100644 --- a/ci/classic.travis +++ b/ci/classic.travis @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -e - DRIVER_PATH="${TRAVIS_BUILD_DIR}/vic/drivers/classic/" DRIVER_EXE="${DRIVER_PATH}vic_classic.exe" SAMPLES_PATH="${TRAVIS_BUILD_DIR}/samples/" diff --git a/ci/image.travis b/ci/image.travis index cac9c9ffc..c37f31411 100644 --- a/ci/image.travis +++ b/ci/image.travis @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -e - DRIVER_PATH="${TRAVIS_BUILD_DIR}/vic/drivers/image/" DRIVER_EXE="${DRIVER_PATH}vic_image.exe" SAMPLES_PATH="${TRAVIS_BUILD_DIR}/samples/" diff --git a/ci/vic_install_utils b/ci/vic_install_utils index a4bca718e..0683f571c 100644 --- a/ci/vic_install_utils +++ b/ci/vic_install_utils @@ -1,7 +1,5 @@ #!/usr/bin/env bash -set -e - if [ -z "$WORKDIR" ]; then export WORKDIR=$HOME/workdir mkdir -p $WORKDIR @@ -10,9 +8,9 @@ fi export VIC_VALGRIND_SUPPRESSIONS=${TRAVIS_BUILD_DIR}/tests/vic_valgrind_suppressions.supp function install_mpich { - wget --no-check-certificate -q http://www.mpich.org/static/downloads/3.2/mpich-3.2.tar.gz - tar -xzf mpich-3.2.tar.gz - cd mpich-3.2 + wget --no-check-certificate -q http://www.mpich.org/static/downloads/3.1b1/mpich-3.1b1.tar.gz + tar -xzf mpich-3.1b1.tar.gz + cd mpich-3.1b1 mkdir build && cd build ../configure CC=$CC CXX=$CXX --prefix=${TRAVIS_MPIPATH} make -j2 From 53bf4d188503314f870e2ab40b6f411ab6f19120 Mon Sep 17 00:00:00 2001 From: Wietse Franssen Date: Fri, 29 Jul 2016 23:38:18 +0200 Subject: [PATCH 22/33] smaller/greater than sign switched (#561) --- vic/drivers/shared_image/src/check_domain_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vic/drivers/shared_image/src/check_domain_info.c b/vic/drivers/shared_image/src/check_domain_info.c index 32d6aa61a..1095b05a9 100644 --- a/vic/drivers/shared_image/src/check_domain_info.c +++ b/vic/drivers/shared_image/src/check_domain_info.c @@ -58,7 +58,7 @@ compare_ncdomain_with_global_domain(char *ncfile) // loop over all grid cells and check that the two domains are identical for (i = 0; i < global_domain.ncells_total; i++) { // mask matches - if (ncfile_domain.locations[i].run > global_domain.locations[i].run) { + if (ncfile_domain.locations[i].run < global_domain.locations[i].run) { log_err("parameter file mask for gridcell %zu is zero and the " "domain file specifies that this cell should be run", i); } From a53f273fec08317cb0f02e07fc73a9e6e8bf311b Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 4 Aug 2016 00:29:03 -0700 Subject: [PATCH 23/33] run uncrustify on all sources, fix some formating in timers --- vic/drivers/classic/src/vic_classic_timing.c | 27 ++++++++++++------- vic/drivers/image/src/vic_image.c | 3 ++- .../shared_image/src/vic_image_timing.c | 27 ++++++++++++------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/vic/drivers/classic/src/vic_classic_timing.c b/vic/drivers/classic/src/vic_classic_timing.c index 0a4cae832..275a06d4d 100644 --- a/vic/drivers/classic/src/vic_classic_timing.c +++ b/vic/drivers/classic/src/vic_classic_timing.c @@ -113,22 +113,31 @@ write_vic_timing_table(timer_struct *timers) nyears / (timers[TIMER_VIC_ALL].delta_wall / SEC_PER_DAY)); fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, " Timing Table:\n"); - fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); - fprintf(LOG_DEST, "| Timer | Wall Time (secs) | CPU Time (secs) | Wall Time (secs/day) | CPU Time (secs/day) |\n"); - fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, + "| Timer | Wall Time (secs) | CPU Time (secs) | Wall Time (secs/day) | CPU Time (secs/day) |\n"); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); fprintf(LOG_DEST, "| Init Time | %20g | %20g | %20g | %20g |\n", timers[TIMER_VIC_INIT].delta_wall, timers[TIMER_VIC_INIT].delta_cpu, - timers[TIMER_VIC_INIT].delta_wall / ndays, timers[TIMER_VIC_INIT].delta_cpu / ndays); + timers[TIMER_VIC_INIT].delta_wall / ndays, + timers[TIMER_VIC_INIT].delta_cpu / ndays); fprintf(LOG_DEST, "| Run Time | %20g | %20g | %20g | %20g |\n", timers[TIMER_VIC_RUN].delta_wall, timers[TIMER_VIC_RUN].delta_cpu, - timers[TIMER_VIC_RUN].delta_wall / ndays, timers[TIMER_VIC_RUN].delta_cpu / ndays); + timers[TIMER_VIC_RUN].delta_wall / ndays, + timers[TIMER_VIC_RUN].delta_cpu / ndays); fprintf(LOG_DEST, "| Final Time | %20g | %20g | %20g | %20g |\n", - timers[TIMER_VIC_FINAL].delta_wall, timers[TIMER_VIC_FINAL].delta_cpu, - timers[TIMER_VIC_FINAL].delta_wall / ndays, timers[TIMER_VIC_FINAL].delta_cpu / ndays); + timers[TIMER_VIC_FINAL].delta_wall, + timers[TIMER_VIC_FINAL].delta_cpu, + timers[TIMER_VIC_FINAL].delta_wall / ndays, + timers[TIMER_VIC_FINAL].delta_cpu / ndays); fprintf(LOG_DEST, "| Total Time | %20g | %20g | %20g | %20g |\n", timers[TIMER_VIC_ALL].delta_wall, timers[TIMER_VIC_ALL].delta_cpu, - timers[TIMER_VIC_ALL].delta_wall / ndays, timers[TIMER_VIC_ALL].delta_cpu / ndays); - fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + timers[TIMER_VIC_ALL].delta_wall / ndays, + timers[TIMER_VIC_ALL].delta_cpu / ndays); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index 163839095..5e92219ed 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -120,7 +120,8 @@ main(int argc, vic_init_output(&(dmy[0])); // Initialization is complete, print settings - log_info("Initialization is complete, print global param and options structures"); + log_info( + "Initialization is complete, print global param and options structures"); print_global_param(&global_param); print_option(&options); diff --git a/vic/drivers/shared_image/src/vic_image_timing.c b/vic/drivers/shared_image/src/vic_image_timing.c index acd35cc46..64034ddd7 100644 --- a/vic/drivers/shared_image/src/vic_image_timing.c +++ b/vic/drivers/shared_image/src/vic_image_timing.c @@ -121,22 +121,31 @@ write_vic_timing_table(timer_struct *timers, nyears / (timers[TIMER_VIC_ALL].delta_wall / SEC_PER_DAY)); fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, " Timing Table:\n"); - fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); - fprintf(LOG_DEST, "| Timer | Wall Time (secs) | CPU Time (secs) | Wall Time (secs/day) | CPU Time (secs/day) |\n"); - fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, + "| Timer | Wall Time (secs) | CPU Time (secs) | Wall Time (secs/day) | CPU Time (secs/day) |\n"); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); fprintf(LOG_DEST, "| Init Time | %20g | %20g | %20g | %20g |\n", timers[TIMER_VIC_INIT].delta_wall, timers[TIMER_VIC_INIT].delta_cpu, - timers[TIMER_VIC_INIT].delta_wall / ndays, timers[TIMER_VIC_INIT].delta_cpu / ndays); + timers[TIMER_VIC_INIT].delta_wall / ndays, + timers[TIMER_VIC_INIT].delta_cpu / ndays); fprintf(LOG_DEST, "| Run Time | %20g | %20g | %20g | %20g |\n", timers[TIMER_VIC_RUN].delta_wall, timers[TIMER_VIC_RUN].delta_cpu, - timers[TIMER_VIC_RUN].delta_wall / ndays, timers[TIMER_VIC_RUN].delta_cpu / ndays); + timers[TIMER_VIC_RUN].delta_wall / ndays, + timers[TIMER_VIC_RUN].delta_cpu / ndays); fprintf(LOG_DEST, "| Final Time | %20g | %20g | %20g | %20g |\n", - timers[TIMER_VIC_FINAL].delta_wall, timers[TIMER_VIC_FINAL].delta_cpu, - timers[TIMER_VIC_FINAL].delta_wall / ndays, timers[TIMER_VIC_FINAL].delta_cpu / ndays); + timers[TIMER_VIC_FINAL].delta_wall, + timers[TIMER_VIC_FINAL].delta_cpu, + timers[TIMER_VIC_FINAL].delta_wall / ndays, + timers[TIMER_VIC_FINAL].delta_cpu / ndays); fprintf(LOG_DEST, "| Total Time | %20g | %20g | %20g | %20g |\n", timers[TIMER_VIC_ALL].delta_wall, timers[TIMER_VIC_ALL].delta_cpu, - timers[TIMER_VIC_ALL].delta_wall / ndays, timers[TIMER_VIC_ALL].delta_cpu / ndays); - fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + timers[TIMER_VIC_ALL].delta_wall / ndays, + timers[TIMER_VIC_ALL].delta_cpu / ndays); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, From 101887dab67867350a2aa2b5297ec35bb91a6d8e Mon Sep 17 00:00:00 2001 From: yixinmao Date: Thu, 4 Aug 2016 15:59:34 -0700 Subject: [PATCH 24/33] Fixed bugs related to ice heat capacity (#570) * Fixed bugs related to ice heat capacity - In vic_run code, fixed bugs that confused volumetric heat capacity and specific heat capacity related to ice * Combine the volumetric ice heat capacity (per volume of water equivalent) into a single constant --- vic/vic_run/include/vic_physical_constants.h | 2 ++ vic/vic_run/src/SnowPackEnergyBalance.c | 4 +-- vic/vic_run/src/calc_surf_energy_bal.c | 3 ++- vic/vic_run/src/func_surf_energy_bal.c | 8 +++--- vic/vic_run/src/ice_melt.c | 26 +++++++++++--------- vic/vic_run/src/snow_melt.c | 22 ++++++++--------- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/vic/vic_run/include/vic_physical_constants.h b/vic/vic_run/include/vic_physical_constants.h index 6aeaaf436..307b82be3 100644 --- a/vic/vic_run/include/vic_physical_constants.h +++ b/vic/vic_run/include/vic_physical_constants.h @@ -108,6 +108,8 @@ #define CONST_CPFW 4.188e3 /**< specific heat of fresh h2o ~ J/kg/K */ #define CONST_CPFWICE 4.2e3 /**< specific heat of fresh h2o ~ J/kg/K */ #define CONST_CPICE 2.11727e3 /**< specific heat of fresh ice ~ J/kg/K */ +/**< volumetric heats */ +#define CONST_VCPICE_WQ (CONST_CPICE * CONST_RHOFW) /**< heat capacity of fresh ice per volume of water equivalent ~ J/m^3/K */ /**< latent heats */ #define CONST_LATICE 3.337e5 /**< latent heat of fusion ~ J/kg */ #define CONST_LATVAP 2.501e6 /**< latent heat of evaporation ~ J/kg */ diff --git a/vic/vic_run/src/SnowPackEnergyBalance.c b/vic/vic_run/src/SnowPackEnergyBalance.c index bd9cfd0f1..f241ee088 100644 --- a/vic/vic_run/src/SnowPackEnergyBalance.c +++ b/vic/vic_run/src/SnowPackEnergyBalance.c @@ -245,8 +245,8 @@ SnowPackEnergyBalance(double TSurf, } /* Calculate change in cold content */ - *DeltaColdContent = CONST_CPICE * SweSurfaceLayer * (TSurf - OldTSurf) / - (Dt); + *DeltaColdContent = CONST_VCPICE_WQ * SweSurfaceLayer * + (TSurf - OldTSurf) / (Dt); /* Calculate Ground Heat Flux */ if (SnowDepth > 0.) { diff --git a/vic/vic_run/src/calc_surf_energy_bal.c b/vic/vic_run/src/calc_surf_energy_bal.c index 6d2e25634..642daee3d 100644 --- a/vic/vic_run/src/calc_surf_energy_bal.c +++ b/vic/vic_run/src/calc_surf_energy_bal.c @@ -690,7 +690,8 @@ calc_surf_energy_bal(double Le, if (snow->swq > 0) { // set snow energy terms snow->surf_temp = (Tsurf > 0) ? 0 : Tsurf; - snow->coldcontent = CONST_CPICE * snow->surf_temp * snow->swq; + snow->coldcontent = CONST_VCPICE_WQ * snow->surf_temp * + snow->swq; // recompute snow depth old_depth = snow->depth; diff --git a/vic/vic_run/src/func_surf_energy_bal.c b/vic/vic_run/src/func_surf_energy_bal.c index 328472ab5..fa828f490 100644 --- a/vic/vic_run/src/func_surf_energy_bal.c +++ b/vic/vic_run/src/func_surf_energy_bal.c @@ -642,12 +642,12 @@ func_surf_energy_bal(double Ts, /* if thin snowpack, compute the change in energy stored in the pack */ if (INCLUDE_SNOW) { if (TMean > 0.) { - *deltaCC = CONST_CPICE * - (snow_swq - snow_water) * (0. - OldTSurf) / delta_t; + *deltaCC = CONST_VCPICE_WQ * (snow_swq - snow_water) * + (0. - OldTSurf) / delta_t; } else { - *deltaCC = CONST_CPICE * - (snow_swq - snow_water) * (TMean - OldTSurf) / delta_t; + *deltaCC = CONST_VCPICE_WQ * (snow_swq - snow_water) * + (TMean - OldTSurf) / delta_t; } *refreeze_energy = (snow_water * CONST_LATICE * snow_density) / delta_t; *deltaCC *= snow_coverage; // adjust for snow cover fraction diff --git a/vic/vic_run/src/ice_melt.c b/vic/vic_run/src/ice_melt.c index 13bb52e39..9e906f338 100644 --- a/vic/vic_run/src/ice_melt.c +++ b/vic/vic_run/src/ice_melt.c @@ -137,13 +137,13 @@ ice_melt(double z2, } /* Calculate cold contents */ - SurfaceCC = CONST_CPICE * SurfaceSwq * snow->surf_temp; - PackCC = CONST_CPICE * (PackSwq + PackIce) * snow->pack_temp; + SurfaceCC = CONST_VCPICE_WQ * SurfaceSwq * snow->surf_temp; + PackCC = CONST_VCPICE_WQ * (PackSwq + PackIce) * snow->pack_temp; if (air_temp > 0.0) { SnowFallCC = 0.0; } else { - SnowFallCC = CONST_CPICE * SnowFall * air_temp; + SnowFallCC = CONST_VCPICE_WQ * SnowFall * air_temp; } /* Distribute fresh snowfall */ @@ -171,13 +171,14 @@ ice_melt(double z2, DeltaPackCC = 0; } if (SurfaceSwq > 0.0) { - snow->surf_temp = SurfaceCC / (CONST_CPICE * SurfaceSwq); + snow->surf_temp = SurfaceCC / (CONST_VCPICE_WQ * SurfaceSwq); } else { snow->surf_temp = 0.0; } if (PackSwq + PackIce > 0.0) { - snow->pack_temp = PackCC / (CONST_CPICE * (PackSwq + PackIce)); + snow->pack_temp = PackCC / + (CONST_VCPICE_WQ * (PackSwq + PackIce)); } else { snow->pack_temp = 0.0; @@ -508,8 +509,10 @@ ice_melt(double z2, if (PackSwq + PackIce > 0.0) { PackCC = (PackSwq + - PackIce) * CONST_CPICE * snow->pack_temp + PackRefreezeEnergy; - snow->pack_temp = PackCC / (CONST_CPICE * (PackSwq + PackIce)); + PackIce) * CONST_VCPICE_WQ * snow->pack_temp + + PackRefreezeEnergy; + snow->pack_temp = PackCC / (CONST_VCPICE_WQ * + (PackSwq + PackIce)); if (snow->pack_temp > 0.) { snow->pack_temp = 0.; } @@ -545,8 +548,8 @@ ice_melt(double z2, /* Update snow properties */ Ice = PackIce + PackSwq + SurfaceSwq; if (Ice > param.SNOW_MAX_SURFACE_SWE) { - SurfaceCC = CONST_CPICE * snow->surf_temp * SurfaceSwq; - PackCC = CONST_CPICE * snow->pack_temp * (PackSwq + PackIce); + SurfaceCC = CONST_VCPICE_WQ * snow->surf_temp * SurfaceSwq; + PackCC = CONST_VCPICE_WQ * snow->pack_temp * (PackSwq + PackIce); if (SurfaceSwq > param.SNOW_MAX_SURFACE_SWE) { PackCC += SurfaceCC * (SurfaceSwq - param.SNOW_MAX_SURFACE_SWE) / SurfaceSwq; @@ -565,8 +568,9 @@ ice_melt(double z2, PackSwq -= param.SNOW_MAX_SURFACE_SWE - SurfaceSwq; SurfaceSwq += param.SNOW_MAX_SURFACE_SWE - SurfaceSwq; } - snow->pack_temp = PackCC / (CONST_CPICE * (PackSwq + PackIce)); - snow->surf_temp = SurfaceCC / (CONST_CPICE * SurfaceSwq); + snow->pack_temp = PackCC / (CONST_VCPICE_WQ * + (PackSwq + PackIce)); + snow->surf_temp = SurfaceCC / (CONST_VCPICE_WQ * SurfaceSwq); } else { PackSwq = 0.0; diff --git a/vic/vic_run/src/snow_melt.c b/vic/vic_run/src/snow_melt.c index d73bfcb7a..ff0b598ab 100644 --- a/vic/vic_run/src/snow_melt.c +++ b/vic/vic_run/src/snow_melt.c @@ -122,13 +122,13 @@ snow_melt(double Le, PackSwq = Ice - SurfaceSwq; /* Calculate cold contents */ - SurfaceCC = CONST_CPFWICE * SurfaceSwq * snow->surf_temp; - PackCC = CONST_CPFWICE * PackSwq * snow->pack_temp; + SurfaceCC = CONST_VCPICE_WQ * SurfaceSwq * snow->surf_temp; + PackCC = CONST_VCPICE_WQ * PackSwq * snow->pack_temp; if (air_temp > 0.0) { SnowFallCC = 0.0; } else { - SnowFallCC = CONST_CPFWICE * SnowFall * air_temp; + SnowFallCC = CONST_VCPICE_WQ * SnowFall * air_temp; } /* Distribute fresh snowfall */ @@ -153,13 +153,13 @@ snow_melt(double Le, SurfaceCC += SnowFallCC; } if (SurfaceSwq > 0.0) { - snow->surf_temp = SurfaceCC / (CONST_CPFWICE * SurfaceSwq); + snow->surf_temp = SurfaceCC / (CONST_VCPICE_WQ * SurfaceSwq); } else { snow->surf_temp = 0.0; } if (PackSwq > 0.0) { - snow->pack_temp = PackCC / (CONST_CPFWICE * PackSwq); + snow->pack_temp = PackCC / (CONST_VCPICE_WQ * PackSwq); } else { snow->pack_temp = 0.0; @@ -415,9 +415,9 @@ snow_melt(double Le, Ice += snow->pack_water; snow->pack_water = 0.0; if (PackSwq > 0.0) { - PackCC = PackSwq * CONST_CPFWICE * snow->pack_temp + + PackCC = PackSwq * CONST_VCPICE_WQ * snow->pack_temp + PackRefreezeEnergy; - snow->pack_temp = PackCC / (CONST_CPFWICE * PackSwq); + snow->pack_temp = PackCC / (CONST_VCPICE_WQ * PackSwq); if (snow->pack_temp > 0.) { snow->pack_temp = 0.; } @@ -456,8 +456,8 @@ snow_melt(double Le, Ice = PackSwq + SurfaceSwq; if (Ice > param.SNOW_MAX_SURFACE_SWE) { - SurfaceCC = CONST_CPFWICE * snow->surf_temp * SurfaceSwq; - PackCC = CONST_CPFWICE * snow->pack_temp * PackSwq; + SurfaceCC = CONST_VCPICE_WQ * snow->surf_temp * SurfaceSwq; + PackCC = CONST_VCPICE_WQ * snow->pack_temp * PackSwq; if (SurfaceSwq > param.SNOW_MAX_SURFACE_SWE) { PackCC += SurfaceCC * (SurfaceSwq - param.SNOW_MAX_SURFACE_SWE) / SurfaceSwq; @@ -474,8 +474,8 @@ snow_melt(double Le, PackSwq -= param.SNOW_MAX_SURFACE_SWE - SurfaceSwq; SurfaceSwq += param.SNOW_MAX_SURFACE_SWE - SurfaceSwq; } - snow->pack_temp = PackCC / (CONST_CPFWICE * PackSwq); - snow->surf_temp = SurfaceCC / (CONST_CPFWICE * SurfaceSwq); + snow->pack_temp = PackCC / (CONST_VCPICE_WQ * PackSwq); + snow->surf_temp = SurfaceCC / (CONST_VCPICE_WQ * SurfaceSwq); } else { PackSwq = 0.0; From b9a719e3ab784c385baf3633f4e3f3f981ee3f76 Mon Sep 17 00:00:00 2001 From: ymao Date: Fri, 5 Aug 2016 18:08:49 -0700 Subject: [PATCH 25/33] Fixed a bug related to VP - to be consistent with VIC4.2 - When calculated VPD < 0, now resets VPD to zero, and VP to calculated saturated vapor pressure (this is consistent with VIC4.2) --- vic/drivers/classic/src/vic_force.c | 4 ++++ vic/drivers/image/src/vic_force.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/vic/drivers/classic/src/vic_force.c b/vic/drivers/classic/src/vic_force.c index 6f361f06f..5e8a96ed2 100644 --- a/vic/drivers/classic/src/vic_force.c +++ b/vic/drivers/classic/src/vic_force.c @@ -138,6 +138,10 @@ vic_force(force_data_struct *force, force[rec].vp[i] = forcing_data[VP][uidx] * PA_PER_KPA; // vapor pressure deficit in Pa force[rec].vpd[i] = svp(force[rec].air_temp[i]) - force[rec].vp[i]; + if (force[rec].vpd[i] < 0) { + force[rec].vpd[i] = 0; + force[rec].vp[i] = svp(force[rec].air_temp[i]); + } // air density in kg/m3 force[rec].density[i] = air_density(force[rec].air_temp[i], force[rec].pressure[i]); diff --git a/vic/drivers/image/src/vic_force.c b/vic/drivers/image/src/vic_force.c index baa6f2a6c..9184a156f 100644 --- a/vic/drivers/image/src/vic_force.c +++ b/vic/drivers/image/src/vic_force.c @@ -366,6 +366,10 @@ vic_force(void) force[i].vp[j] = q_to_vp(force[i].vp[j], force[i].pressure[j]); // vapor pressure deficit in Pa force[i].vpd[j] = svp(force[i].air_temp[j]) - force[i].vp[j]; + if (force[i].vpd[j] < 0) { + force[i].vpd[j] = 0; + force[i].vp[j] = svp(force[i].air_temp[j]); + } // air density in kg/m3 force[i].density[j] = air_density(force[i].air_temp[j], force[i].pressure[j]); From 57b8d18563ca53367ca9234c4d76ee74a209f12a Mon Sep 17 00:00:00 2001 From: Diana Gergel Date: Tue, 9 Aug 2016 23:59:17 -0700 Subject: [PATCH 26/33] Feature/add science testing (#544) * added global parameter files for snotel forcings for vic 4.2 and 5.0 * remove hard-coded paths and made LAI_SRC the same for both versions * updated LAI_SRC option * cleaned up global parameter files for 4.2 and 5.0 * added global parameter files for Ameriflux simulations for 4.2 and 5.0 * Revert "added global parameter files for Ameriflux simulations for 4.2 and 5.0" This reverts commit 60ca012bcdf1266ecbf60d4a4fb47f8bfbe5113c. * add global parameter files for Ameriflux simulations * add config file for science testing * refactored science testing config file * added science test plots * added main science plots function and snotel plotting function * finished adding plot_snotel_comparison function * added string splitting function * add constants file to science testing to help replicate VIC 4.2 results * added fluxnet plot function and annual mean diurnal cycle section * added monthly mean diurnal cycle section to plot fluxnet function * add optional argument for science testing directory * updated to only include one output file for both snow and energy balance output variables * fixing up paths for science testing * further fixing of paths * updated global parameter files and minor bug fixes * added matplotlib to required dependencies * cleaned up global parameter files and updated precision for outvars in output files * refactored science testing by separating reading functions and plotting functions * remove print statement * updated config file to include multi-level options * removed warnings from requirements * fix science test data directory check * fixed typo on vic_parameters comparison to 42 file * fix bug in science test directory check * updated read_vic_ascii file and added output file nans check back in * remove print statement * fix bug in read_vic_ascii function * fix travis build * updated plotting functionality and formatting of vic output read functions * further resolution of merge conflict * update VIC 5 runs to include VIC 4.2 parameters (to account for difference in emissivity value) * updated radiation output variable names * typo in outputting net longwave radiation * fix more typos in global parameter files for net shortwave and longwave output * minor updates due to changes in VIC classic driver since test simulations were last run * fixed pep8 issues as well as other formatting problems * changed name of VIC 42 compatible parameters file * remove old VIC 42 parameters file * additional formatting changes and updates to the datetime indexing of the ascii vic output and snotel obs reader functions * fix travis build * updated vic 42 constants file * fix small bug in read_snotel_swe_obs --- ci/requirements.yml | 2 + tests/run_tests.py | 62 +- .../global_param.classic.4.2_ecflux.txt | 106 ++++ .../global_param.classic.4.2_snotel.txt | 100 ++++ .../global_param.classic.5.0_ecflux.txt | 102 ++++ .../global_param.classic.5.0_snotel.txt | 84 +++ tests/science/science.cfg | 66 ++- tests/science/vic_parameters_42_compat.txt | 279 +++++++++ tests/test_utils.py | 531 +++++++++++++++++- 9 files changed, 1301 insertions(+), 31 deletions(-) create mode 100644 tests/science/global_param.classic.4.2_ecflux.txt create mode 100644 tests/science/global_param.classic.4.2_snotel.txt create mode 100644 tests/science/global_param.classic.5.0_ecflux.txt create mode 100644 tests/science/global_param.classic.5.0_snotel.txt create mode 100644 tests/science/vic_parameters_42_compat.txt diff --git a/ci/requirements.yml b/ci/requirements.yml index cbc696634..a7caa8514 100644 --- a/ci/requirements.yml +++ b/ci/requirements.yml @@ -10,6 +10,8 @@ dependencies: - configobj - xarray - bottleneck + - matplotlib + - seaborn - psutil - pip: - git+https://github.com/UW-Hydro/tonic.git diff --git a/tests/run_tests.py b/tests/run_tests.py index 6bcc99d27..afbddaa5b 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -22,7 +22,8 @@ test_classic_driver_all_complete, test_classic_driver_no_output_file_nans, find_global_param_value, - check_multistream_classic) + check_multistream_classic, + plot_science_tests) from test_image_driver import (test_image_driver_no_output_file_nans, check_multistream_image, setup_subdirs_and_fill_in_global_param_mpi_test, @@ -147,7 +148,11 @@ def main(): default='$WORKDIR/VIC_tests_{0}'.format(ymd)) parser.add_argument('--data_dir', type=str, help='directory to find test data', - default=os.path.join(test_dir, '../samples/VIC_sample_data')) + default='./samples/VIC_sample_data') + parser.add_argument('--science_test_data_dir', type=str, + help='directory to find science test data', + default='./samples/VIC_sample_data') + args = parser.parse_args() # Define test directories @@ -155,6 +160,11 @@ def main(): out_dir = os.path.expandvars(args.output_dir) os.makedirs(out_dir, exist_ok=True) + # check to make sure science test data directory exists + science_test_data_dir = args.science_test_data_dir + if 'science' in args.tests and not os.path.exists(science_test_data_dir): + raise VICTestError("directory for science test data does not exist or has not been defined") + # Validate input directories if not (len(args.tests) == 1 and args.tests[0] == 'unit'): for d in [data_dir, test_dir]: @@ -183,7 +193,9 @@ def main(): args.driver) # science if any(i in ['all', 'science'] for i in args.tests): - test_results['science'] = run_science(args.science, vic_exe, data_dir, + test_results['science'] = run_science(args.science, vic_exe, + science_test_data_dir, + data_dir, os.path.join(out_dir, 'science'), args.driver) # examples @@ -541,7 +553,8 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): return test_results -def run_science(config_file, vic_exe, test_data_dir, out_dir, driver): +def run_science(config_file, vic_exe, science_test_data_dir, + test_data_dir, out_dir, driver): '''Run science tests from config file Parameters @@ -550,6 +563,8 @@ def run_science(config_file, vic_exe, test_data_dir, out_dir, driver): Configuration file for science tests. vic_exe : VIC (object) VIC executable object (see tonic documentation). + science_test_data_dir: str + Path to science test data sets (archived VIC runs and observations) test_data_dir : str Path to test data sets. out_dir : str @@ -576,7 +591,7 @@ def run_science(config_file, vic_exe, test_data_dir, out_dir, driver): print('-'.ljust(OUTPUT_WIDTH, '-')) # Get setup - config = read_config(config_file) + config = read_configobj(config_file) # drop invalid driver tests config = drop_tests(config, driver) @@ -584,18 +599,19 @@ def run_science(config_file, vic_exe, test_data_dir, out_dir, driver): test_results = OrderedDict() # Run individual tests - for i, (testname, test_dict) in enumerate(config.items()): + for i, (test_type, test_dict) in enumerate(config.items()): # print out status info print('Running test {0}/{1}: {2}'.format(i + 1, len(config.items()), - testname)) + test_type)) # Setup directories for test - dirs = setup_test_dirs(testname, out_dir, + dirs = setup_test_dirs(test_type, out_dir, mkdirs=['results', 'state', 'logs', 'plots']) # read template global parameter file - infile = os.path.join(test_dir, test_dict['global_parameter_file']) + infile = os.path.join(test_dir, 'science', + test_dict['global_parameter_file']) with open(infile, 'r') as global_file: global_param = global_file.read() @@ -604,14 +620,15 @@ def run_science(config_file, vic_exe, test_data_dir, out_dir, driver): s = string.Template(global_param) # fill in global parameter options - global_param = s.safe_substitute(test_data_dir=test_data_dir, + global_param = s.safe_substitute(test_data_dir=science_test_data_dir, + test_dir=test_dir, result_dir=dirs['results'], state_dir=dirs['state'], - testname=testname, + testname=test_type, test_root=test_dir) test_global_file = os.path.join(dirs['test'], - '{0}_globalparam.txt'.format(testname)) + '{0}_globalparam.txt'.format(test_type)) # write global parameter file with open(test_global_file, 'w') as f: @@ -658,17 +675,26 @@ def run_science(config_file, vic_exe, test_data_dir, out_dir, driver): # if we got this far, the test passed. test_passed = True + # plot science test results + plot_science_tests(test_dict['driver'], + test_type, + science_test_data_dir, + dirs['results'], + dirs['plots'], + test_dict['plots'], + test_dict['compare_data']) + # Handle errors except Exception as e: test_comment, error_message = process_error(e, vic_exe) # record the test results - test_results[testname] = TestResults(testname, - test_complete=test_complete, - passed=test_passed, - comment=test_comment, - error_message=error_message, - returncode=returncode) + test_results[test_type] = TestResults(test_type, + test_complete=test_complete, + passed=test_passed, + comment=test_comment, + error_message=error_message, + returncode=returncode) print('-'.ljust(OUTPUT_WIDTH, '-')) print('Finished testing science tests.') diff --git a/tests/science/global_param.classic.4.2_ecflux.txt b/tests/science/global_param.classic.4.2_ecflux.txt new file mode 100644 index 000000000..0dc459e41 --- /dev/null +++ b/tests/science/global_param.classic.4.2_ecflux.txt @@ -0,0 +1,106 @@ +NLAYER 3 +NODES 3 +TIME_STEP 1 +SNOW_STEP 1 +STARTYEAR 2000 +STARTMONTH 01 +STARTDAY 01 +STARTHOUR 00 +ENDYEAR 2012 +ENDMONTH 12 +ENDDAY 31 + +FULL_ENERGY TRUE +FROZEN_SOIL FALSE + +FORCING1 $test_data_dir/datasets/ec_flux_towers/forcing.merge.hourly/full_data_ +FORCE_FORMAT ASCII +FORCE_ENDIAN LITTLE +N_TYPES 12 +FORCE_TYPE SKIP +FORCE_TYPE SKIP +FORCE_TYPE SKIP +FORCE_TYPE SKIP +FORCE_TYPE PREC UNSIGNED 40 +FORCE_TYPE AIR_TEMP SIGNED 100 +FORCE_TYPE SHORTWAVE SIGNED 100 +FORCE_TYPE LONGWAVE SIGNED 100 +FORCE_TYPE SKIP +FORCE_TYPE PRESSURE SIGNED 100 +FORCE_TYPE VP SIGNED 100 +FORCE_TYPE WIND SIGNED 100 +FORCE_DT 1 +FORCEYEAR 1980 +FORCEMONTH 01 +FORCEDAY 01 +FORCEHOUR 00 +GRID_DECIMAL 4 + +WIND_H 10.0 +MEASURE_H 2.0 +ALMA_INPUT FALSE + +SOIL $test_data_dir/datasets/ec_flux_towers/params/soil_param.site_test.txt +BASEFLOW ARNO +JULY_TAVG_SUPPLIED FALSE +ORGANIC_FRACT FALSE + +VEGLIB $test_data_dir/datasets/ec_flux_towers/params/veg_lib_IGBP.fv +VEGLIB_VEGCOVER TRUE + +VEGPARAM $test_data_dir/datasets/ec_flux_towers/params/veg_param.sites.IGBP.modis +ROOT_ZONES 3 + +VEGPARAM_LAI TRUE +VEGPARAM_VEGCOVER TRUE +VEGPARAM_ALB TRUE + +LAI_SRC FROM_VEGPARAM +VEGCOVER_SRC FROM_VEGPARAM +ALBEDO_SRC FROM_VEGPARAM +SNOW_BAND 1 + + +RESULT_DIR $result_dir +OUT_STEP 1 +SKIPYEAR 0 +COMPRESS FALSE +BINARY_OUTPUT FALSE +ALMA_OUTPUT FALSE +MOISTFRACT FALSE +PRT_HEADER TRUE +PRT_SNOW_BAND FALSE + +N_OUTFILES 2 + +OUTFILE snow 16 +OUTVAR OUT_SWE %.6g * * +OUTVAR OUT_SNOW_DEPTH %.6g * * +OUTVAR OUT_SNOW_CANOPY %.6g * * +OUTVAR OUT_SNOW_COVER %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTACC %.6g * * +OUTVAR OUT_SNOW_FLUX %.6g * * +OUTVAR OUT_RFRZ_ENERGY %.6g * * +OUTVAR OUT_MELT_ENERGY %.6g * * +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_SNOW_SURF_TEMP %.6g * * +OUTVAR OUT_SNOW_PACK_TEMP %.6g * * +OUTVAR OUT_SNOW_MELT %.6g * * +OUTVAR OUT_ALBEDO %.6g * * +OUTVAR OUT_SALBEDO %.6g * * + +OUTFILE en_bal 12 +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTAH %.6g * * +OUTVAR OUT_GRND_FLUX %.6g * * +OUTVAR OUT_IN_LONG %.6g * * +OUTVAR OUT_LATENT %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_R_NET %.6g * * +OUTVAR OUT_SENSIBLE %.6g * * +OUTVAR OUT_RAD_TEMP %.6g * * +OUTVAR OUT_NET_SHORT %.6g * * +OUTVAR OUT_NET_LONG %.6g * * diff --git a/tests/science/global_param.classic.4.2_snotel.txt b/tests/science/global_param.classic.4.2_snotel.txt new file mode 100644 index 000000000..b96323ab0 --- /dev/null +++ b/tests/science/global_param.classic.4.2_snotel.txt @@ -0,0 +1,100 @@ +NLAYER 3 +NODES 10 +TIME_STEP 1 +SNOW_STEP 1 +STARTYEAR 2007 +STARTMONTH 11 +STARTDAY 01 +STARTHOUR 00 +ENDYEAR 2008 +ENDMONTH 07 +ENDDAY 31 + +FULL_ENERGY TRUE +FROZEN_SOIL FALSE + +BLOWING FALSE + +CORRPREC FALSE +MIN_WIND_SPEED 0.1 +MAX_SNOW_TEMP 0.5 +MIN_RAIN_TEMP -0.5 + +CONTINUEONERROR TRUE + +GRND_FLUX_TYPE GF_FULL + +FORCING1 $test_data_dir/datasets/snotel/forcings_vp/snotel_VIC.4.1.2_forcings_ +FORCE_FORMAT ASCII +FORCE_ENDIAN LITTLE +N_TYPES 7 # Number of variables (columns) +FORCE_TYPE SHORTWAVE UNSIGNED 40 +FORCE_TYPE LONGWAVE UNSIGNED 40 +FORCE_TYPE AIR_TEMP SIGNED 100 +FORCE_TYPE PRESSURE UNSIGNED 40 +FORCE_TYPE PREC UNSIGNED 40 +FORCE_TYPE VP UNSIGNED 40 +FORCE_TYPE WIND SIGNED 100 +FORCE_DT 1 +FORCEYEAR 2007 +FORCEMONTH 11 +FORCEDAY 01 +FORCEHOUR 00 +GRID_DECIMAL 4 +WIND_H 17.5 +MEASURE_H 17.5 +ALMA_INPUT FALSE + +SOIL $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_soil.txt +BASEFLOW ARNO + +JULY_TAVG_SUPPLIED FALSE +VEGLIB $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_veglib.txt +VEGPARAM $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_vegparam.txt +ROOT_ZONES 3 + +VEGPARAM_LAI TRUE +LAI_SRC FROM_VEGPARAM + +SNOW_BAND 1 + +RESULT_DIR $result_dir +OUT_STEP 24 +SKIPYEAR 0 +COMPRESS FALSE +BINARY_OUTPUT FALSE +ALMA_OUTPUT FALSE +MOISTFRACT FALSE +PRT_HEADER TRUE +PRT_SNOW_BAND FALSE + + +N_OUTFILES 1 + +OUTFILE outfile 26 +OUTVAR OUT_SWE %.6g * * +OUTVAR OUT_SNOW_DEPTH %.6g * * +OUTVAR OUT_SNOW_CANOPY %.6g * * +OUTVAR OUT_SNOW_COVER %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTACC %.6g * * +OUTVAR OUT_SNOW_FLUX %.6g * * +OUTVAR OUT_RFRZ_ENERGY %.6g * * +OUTVAR OUT_MELT_ENERGY %.6g * * +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_SNOW_SURF_TEMP %.6g * * +OUTVAR OUT_SNOW_PACK_TEMP %.6g * * +OUTVAR OUT_SNOW_MELT %.6g * * +OUTVAR OUT_ALBEDO %.6g * * +OUTVAR OUT_SALBEDO %.6g * * +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTAH %.6g * * +OUTVAR OUT_GRND_FLUX %.6g * * +OUTVAR OUT_IN_LONG %.6g * * +OUTVAR OUT_LATENT %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_R_NET %.6g * * +OUTVAR OUT_SENSIBLE %.6g * * +OUTVAR OUT_RAD_TEMP %.6g * * diff --git a/tests/science/global_param.classic.5.0_ecflux.txt b/tests/science/global_param.classic.5.0_ecflux.txt new file mode 100644 index 000000000..f961d67c5 --- /dev/null +++ b/tests/science/global_param.classic.5.0_ecflux.txt @@ -0,0 +1,102 @@ +NLAYER 3 +NODES 10 +MODEL_STEPS_PER_DAY 24 +SNOW_STEPS_PER_DAY 24 +RUNOFF_STEPS_PER_DAY 24 +STARTYEAR 2000 +STARTMONTH 01 +STARTDAY 01 +STARTSEC 00 +ENDYEAR 2012 +ENDMONTH 12 +ENDDAY 31 + +FULL_ENERGY TRUE +FROZEN_SOIL FALSE + +QUICK_FLUX FALSE + +FORCING1 $test_data_dir/datasets/ec_flux_towers/forcing.merge.hourly/full_data_ +FORCE_FORMAT ASCII +FORCE_TYPE SKIP +FORCE_TYPE SKIP +FORCE_TYPE SKIP +FORCE_TYPE SKIP +FORCE_TYPE PREC UNSIGNED 40 +FORCE_TYPE AIR_TEMP SIGNED 100 +FORCE_TYPE SWDOWN SIGNED 100 +FORCE_TYPE LWDOWN SIGNED 100 +FORCE_TYPE SKIP +FORCE_TYPE PRESSURE SIGNED 100 +FORCE_TYPE VP SIGNED 100 +FORCE_TYPE WIND SIGNED 100 +FORCE_STEPS_PER_DAY 24 +FORCEYEAR 1980 +FORCEMONTH 01 +FORCEDAY 01 +GRID_DECIMAL 4 + +WIND_H 10.0 + +SOIL $test_data_dir/datasets/ec_flux_towers/params/soil_param.site_test.txt +BASEFLOW ARNO +JULY_TAVG_SUPPLIED FALSE +ORGANIC_FRACT FALSE + +VEGLIB $test_data_dir/datasets/ec_flux_towers/params/veg_lib_IGBP.fv +VEGLIB_FCAN TRUE + +VEGPARAM $test_data_dir/datasets/ec_flux_towers/params/veg_param.sites.IGBP.modis +ROOT_ZONES 3 + +VEGPARAM_LAI TRUE +VEGPARAM_FCAN TRUE +VEGPARAM_ALB TRUE + +LAI_SRC FROM_VEGPARAM +FCAN_SRC FROM_VEGPARAM +# ALBEDO_SRC FROM_VEGPARAM + +SNOW_BAND 1 + +RESULT_DIR $result_dir + +CONSTANTS $test_dir/science/vic_parameters_42_compat.txt + +OUTFILE snow 16 +AGGFREQ NHOURS +COMPRESS FALSE +OUT_FORMAT ASCII +OUTVAR OUT_SWE %.6g * * +OUTVAR OUT_SNOW_DEPTH %.6g * * +OUTVAR OUT_SNOW_CANOPY %.6g * * +OUTVAR OUT_SNOW_COVER %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTACC %.6g * * +OUTVAR OUT_SNOW_FLUX %.6g * * +OUTVAR OUT_RFRZ_ENERGY %.6g * * +OUTVAR OUT_MELT_ENERGY %.6g * * +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_SNOW_SURF_TEMP %.6g * * +OUTVAR OUT_SNOW_PACK_TEMP %.6g * * +OUTVAR OUT_SNOW_MELT %.6g * * +OUTVAR OUT_ALBEDO %.6g * * +OUTVAR OUT_SALBEDO %.6g * * + +OUTFILE en_bal 12 +AGGFREQ NHOURS +COMPRESS FALSE +OUT_FORMAT ASCII +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTAH %.6g * * +OUTVAR OUT_GRND_FLUX %.6g * * +OUTVAR OUT_IN_LONG %.6g * * +OUTVAR OUT_LATENT %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_R_NET %.6g * * +OUTVAR OUT_SENSIBLE %.6g * * +OUTVAR OUT_RAD_TEMP %.6g * * +OUTVAR OUT_SWNET %.6g * * +OUTVAR OUT_LWNET %.6g * * diff --git a/tests/science/global_param.classic.5.0_snotel.txt b/tests/science/global_param.classic.5.0_snotel.txt new file mode 100644 index 000000000..604d7c26e --- /dev/null +++ b/tests/science/global_param.classic.5.0_snotel.txt @@ -0,0 +1,84 @@ +NLAYER 3 +NODES 10 +MODEL_STEPS_PER_DAY 24 +SNOW_STEPS_PER_DAY 24 +RUNOFF_STEPS_PER_DAY 24 +STARTYEAR 2007 +STARTMONTH 11 +STARTDAY 01 +STARTSEC 00 +ENDYEAR 2008 +ENDMONTH 07 +ENDDAY 31 + +FULL_ENERGY TRUE +FROZEN_SOIL FALSE + +QUICK_FLUX FALSE + +FORCING1 $test_data_dir/datasets/snotel/forcings_vp/snotel_VIC.4.1.2_forcings_ +FORCE_FORMAT ASCII +FORCE_TYPE SWDOWN +FORCE_TYPE LWDOWN +FORCE_TYPE AIR_TEMP +FORCE_TYPE PRESSURE +FORCE_TYPE PREC +FORCE_TYPE VP +FORCE_TYPE WIND + +FORCE_STEPS_PER_DAY 24 +FORCEYEAR 2007 +FORCEMONTH 11 +FORCEDAY 01 +GRID_DECIMAL 4 +WIND_H 17.5 + +SOIL $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_soil.txt +BASEFLOW ARNO + +JULY_TAVG_SUPPLIED FALSE +ORGANIC_FRACT FALSE + +VEGLIB $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_veglib.txt +VEGPARAM $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_vegparam.txt +ROOT_ZONES 3 + +VEGPARAM_LAI TRUE +LAI_SRC FROM_VEGPARAM + +SNOW_BAND 1 + +RESULT_DIR $result_dir + +CONSTANTS $test_dir/science/vic_parameters_42_compat.txt + +OUTFILE outfile 24 +AGGFREQ NDAYS +COMPRESS FALSE +OUT_FORMAT ASCII +OUTVAR OUT_SWE %.6g * * +OUTVAR OUT_SNOW_DEPTH %.6g * * +OUTVAR OUT_SNOW_CANOPY %.6g * * +OUTVAR OUT_SNOW_COVER %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTACC %.6g * * +OUTVAR OUT_SNOW_FLUX %.6g * * +OUTVAR OUT_RFRZ_ENERGY %.6g * * +OUTVAR OUT_MELT_ENERGY %.6g * * +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_SNOW_SURF_TEMP %.6g * * +OUTVAR OUT_SNOW_PACK_TEMP %.6g * * +OUTVAR OUT_SNOW_MELT %.6g * * +OUTVAR OUT_ALBEDO %.6g * * +OUTVAR OUT_SALBEDO %.6g * * +OUTVAR OUT_ADV_SENS %.6g * * +OUTVAR OUT_ADVECTION %.6g * * +OUTVAR OUT_DELTAH %.6g * * +OUTVAR OUT_GRND_FLUX %.6g * * +OUTVAR OUT_IN_LONG %.6g * * +OUTVAR OUT_LATENT %.6g * * +OUTVAR OUT_LATENT_SUB %.6g * * +OUTVAR OUT_R_NET %.6g * * +OUTVAR OUT_SENSIBLE %.6g * * +OUTVAR OUT_RAD_TEMP %.6g * * diff --git a/tests/science/science.cfg b/tests/science/science.cfg index b64aea458..499c140f1 100644 --- a/tests/science/science.cfg +++ b/tests/science/science.cfg @@ -1 +1,65 @@ -[test] +[science_test_snotel] +driver = classic +test_description = snotel point simulations +global_parameter_file = global_param.classic.5.0_snotel.txt +expected_retval = 0 +check = output_file_nans +plots = water_year +[[compare_data]] +[[[VIC.4.2.d]]] +version = 4.2 +archive = vic_4_2 +color = 'b' +linestyle = '-' +linewidth = 4.0 +zorder = 5 +compare_to = snotel +[[[VIC.5.0.0.rc1]]] +version = 5.0 +archive = vic_5_0 +color = 'r' +linestyle = '-' +linewidth = 2.0 +zorder = 10 +compare_to = snotel +[[[snotel]]] +version = None +archive = snotel +color = 'k' +linestyle = '--' +linewidth = 4.0 +zorder = 1 +compare_to = snotel + +[science_test_fluxnet] +driver = classic +test_description = Ameriflux point simulations +global_parameter_file = global_param.classic.5.0_ecflux.txt +expected_retval = 0 +check = output_file_nans +plots = annual_mean_diurnal_cycle, monthly_mean_diurnal_cycle +[[compare_data]] +[[[VIC.4.2.d]]] +version = 4.2 +archive = vic_4_2 +color = 'b' +linestyle = '-' +linewidth = 4.0 +zorder = 5 +compare_to = ecflux +[[[VIC.5.0.0.rc1]]] +version = 5.0 +archive = vic_5_0 +color = 'r' +linestyle = '-' +linewidth = 2.0 +zorder = 10 +compare_to = ecflux +[[[ecflux]]] +version = None +archive = ec_flux_towers +color = 'k' +linestyle = '--' +linewidth = 4.0 +zorder = 1 +compare_to = None diff --git a/tests/science/vic_parameters_42_compat.txt b/tests/science/vic_parameters_42_compat.txt new file mode 100644 index 000000000..fe94a7af0 --- /dev/null +++ b/tests/science/vic_parameters_42_compat.txt @@ -0,0 +1,279 @@ + # @section DESCRIPTION + # + # VIC Model Parameters Namelist + # + # This file includes all physical constants from VIC 4.2 for compatible + # testing between VIC 4.2 and VIC 5.0. + # + # @section LICENSE + # + # The Variable Infiltration Capacity (VIC) macroscale hydrological model + # Copyright (C) 2016 The Computational Hydrology Group, Department of Civil + # and Environmental Engineering, University of Washington. + # + # The VIC model is free software; you can redistribute it and/or + # modify it under the terms of the GNU General Public License + # as published by the Free Software Foundation; either version 2 + # of the License, or (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License along with + # this program; if not, write to the Free Software Foundation, Inc., + # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + ############################################################################## + +############################################################################### +LAPSE_RATE -0.0065 # temperature lapse rate in C/m +############################################################################### + +############################################################################### +ALBEDO_BARE_SOIL 0.2 # albedo for bare soil + +EMISS_GRND 1.0 # Ground emissivity +EMISS_VEG 1.0 # Veg emissivity +EMISS_ICE 0.97 # Ice emissivity +EMISS_SNOW 1.0 # Snow emissivity +############################################################################### + + +DEFAULT_WIND_SPEED 3.0 # Default wind speed [m/s] used when wind is not + # supplied as a forcing + +############################################################################### +# Physical Constraints +SOIL_RESID_MOIST 0.0 # define residual moisture content of soil column +SOIL_SLAB_MOIST_FRACT 1.0 # Volumetric moisture content (fraction of porosity) + # in the soil/rock below the bottom soil layer; this + # assumes that the soil below the bottom layer has + # the same texture as the bottom layer. + +# water holding capacity of snow as a fraction of snow-water-equivalent +VEG_LIQUID_WATER_CAPACITY 0.035 + +# multiplier to calculate the amount of available snow interception as a +#function of LAI (m) +VEG_LAI_SNOW_MULTIPLIER 0.0005 + +# the amount of snow on the canopy that can only be melted off. (m) +VEG_MIN_INTERCEPTION_STORAGE 0.005 + +# Coefficient multiplied by the LAI to determine the amount of water that can +# be stored in the canopy +VEG_LAI_WATER_FACTOR 0.1 +############################################################################### + +############################################################################### +# Canopy Resistance Parameters +CANOPY_CLOSURE 4000.0 # Threshold vapor pressure deficit for stomatal closure (Pa) +CANOPY_RSMAX 5000.0 # Maximum allowable resistance (s/m) +CANOPY_VPDMINFACTOR 0.1 # Minimum allowable vapor pressure deficit factor +############################################################################### + +############################################################################### +# Lake Model Parameters + +# lake model related constants +LAKE_TMELT 0.0 +LAKE_MAX_SURFACE_LAKE 0.6 # max. surface layer thickness for E-B (m) +LAKE_BETA 0.001 # Curve shape parameter for lake profile. +LAKE_FRACMIN 0.10 # min ice thickness in meters +LAKE_FRACLIM 0.02 # lower limit on fractional ice cover +LAKE_DM 1.38889E-07 # molecular diffusivity of water +LAKE_SNOWCRIT 0.05 # for albedo, in m +LAKE_ZWATER 0.0045 # 0.004 - original value +LAKE_ZSNOW 0.005 +LAKE_RHOSNOW 250.0 # densities snow on ice +LAKE_CONDI 2.3 # thermal conductivity of ice +LAKE_CONDS 0.7 # thermal conductivity of snow + +# attenuation of short and longwave radiation through ice (1/m) +LAKE_LAMISW 1.5 # 1.5 in Patterson & Hamblin +LAKE_LAMILW 20.0 # 20.0 in Patterson & Hamblin + +# attenuation of short and longwave radiation through snow (1/m) +LAKE_LAMSSW 6.0 # 6.0 in Patterson & Hamblin +LAKE_LAMSLW 20.0 # 20.0 in Patterson & Hamblin + +# attenuation of short and longwave radiation through water (1/m) +LAKE_LAMWSW 0.3 # San Fran Bay data: 0.31 - 29.9 1/m (visible) +LAKE_LAMWLW 1.4 # Hostetler and Bartlein assume 0.85 1/m (total) +LAKE_A1 0.7 # Fraction of radiation in visible band. +LAKE_A2 0.3 # Fraction of radiation in infrared band. +LAKE_QWTAU 43200.0 # D. Pollard sub-ice time constant. (86400. / 2.) +############################################################################### + +############################################################################### +# Saturated Vapor Pressure Curve Parameters +SVP_A 0.61078 +SVP_B 17.269 +SVP_C 237.3 +############################################################################### + +############################################################################### +# Carbon Cycling constants +CARBON_CATMCURRENT 383.0 # Current global atmospheric CO2 mixing ratio (ppm) +CARBON_SW2PAR 0.45 # Empirical ratio of PAR [W/m2] to SHORTWAVE [W/m2] from Lopez et al., 2001 +############################################################################### + +############################################################################### +# Photosynthesis Parameters +PHOTO_OMEGA 0.12 # single leaf scattering albedo +PHOTO_LAIMAX 8.0 # Maximum LAI in nitrogen scaling +PHOTO_LAILIMIT 3.0 # Minimum LAI in nitrogen scaling and maximum LAI in PAR + # computation +PHOTO_LAIMIN 1.0e-9 # Minimum LAI in PAR computation +PHOTO_EPAR 2.2e5 # Energy content of PAR [J/mol photons] + # = (4.6 mol/MJ PAR)^-1 +PHOTO_FCMAX 0.9 # Maximum fractional veg cover + # (1-FcMax) = min amount of ground visible +PHOTO_FCMIN 1.0e-3 # Minimum fractional veg cover + # (1-FcMin) = max amount of ground visible +PHOTO_ZENITHMIN 0.0174524 # Check for solar zenith angle > 89 deg +PHOTO_ZENITHMINPAR 1.0e-3 # Cosine of the minimum solar zenith angle for + # photosynthesis to take place +PHOTO_ALBSOIPARMIN 0.0 # Minimum soil reflectivity in PAR range +PHOTO_MINMAXETRANS 1e-12 # Minimum of maximum electron transport rate + # [10e-12 mol/(m^2 s)] +PHOTO_MINSTOMCOND 0.0 # Minimum stomatal conductance [mol H2O/m2s] + +# Factors that relate leaf internal CO2 concentration to ambient CO2 +# concentration +PHOTO_FCI1C3 0.87 # C3 Plants +PHOTO_FCI1C4 0.67 # C4 Plants + +# C3 PLANTS: FARQUHAR, G.D., S. VON CAEMMERER AND J.A. BERRY, 1980. A +# BIOCHEMICAL MODEL OF PHOTOYNTHESIS IN LEAVES OF C3 SPECIES. PLANTA 149, +# 78-90. +PHOTO_OX 0.21 # OXYGEN CONCENTRATION [MOL(O2) / MOL(AIR)] +PHOTO_KC0 460.0e-6 # MICHAELIS-MENTEN CONSTANT FOR CO2 AT 25C + # [MOL(CO2) / MOL(AIR)] +PHOTO_KO0 330.0e-3 # MICHAELIS-MENTEN CONSTANT FOR O2 AT 25C + # [MOL(O2) / MOL(AIR)] +PHOTO_EC 59356.0 # ACTIVATION ENERGY FOR KC [J / MOL] +PHOTO_EO 35948.0 # ACTIVATION ENERGY FOR KO [J / MOL] +PHOTO_EV 58520.0 # ACTIVATION ENERGY FOR VCMAX [J / MOL] +PHOTO_ER 45000.0 # ACTIVATION ENERGY FOR DARK RESPIRATION [J / MOL] +PHOTO_ALC3 0.28 # EFFICIENCY OF OF PHOTON CAPTURE +PHOTO_FRDC3 0.011 # RATIO OF DARK RESPIRATION TO "PVM" AT 25C for C3 + +# C4 PLANTS: COLLATZ, G.J., M. RIBAS-CARBO AND J.A. BERRY, 1992. COUPLED +# PHOTOSYNTHESIS-STOMATAL CONDUCTANCE MODEL FOR LEAVES OF C4 PLANTS. AUST. J. +# PLANT PHYSIOL. 19, 519-538. +PHOTO_EK 50967.0 # Q10=2 (Collatz et al. 1992) +PHOTO_ALC4 0.04 # EFFECTIVE QUANTUM EFFICIENCY +PHOTO_FRDC4 0.042 # RATIO OF DARK RESPIRATION TO "PVM" AT 25C for C4 +PHOTO_THETA 0.83 # CURVATURE PARAMETER + +# Plant Maintenance and Growth Respiration Parameters +PHOTO_FRLEAF 0.4 # Ratio of canopy leaf respiration to whole plant + # maintenance respiration +PHOTO_FRGROWTH 0.25 # Ratio of plant growth respiration to NPP +############################################################################### + +############################################################################### +# Soil Respiration Parameters +SRESP_E0_LT 308.56 # Lloyd-Taylor E0 parameter [K] +SRESP_T0_LT 227.13 # Lloyd-Taylor T0 parameter [K] +SRESP_WMINFM 0.0 # minimum soil moisture (fraction) at which soil + # respiration can occur +SRESP_WMAXFM 1.0 # maximum soil moisture (fraction) at which soil + # respiration can occur +SRESP_WOPTFM 0.5 # soil moisture (fraction) at which maximum soil + # respiration occurs +SRESP_RHSAT 0.15 # ratio of soil respiration rate under saturated conditions + # (w=wmaxFM) to that under optimal conditions (w=woptFM) +SRESP_RFACTOR 0.5 # scaling factor to account for other (non-moisture) + # sources of inhibition of respiration +SRESP_TAULITTER 2.86 # Litter pool turnover time [y] +SRESP_TAUINTER 33.3 # Intermediate pool turnover time [y] +SRESP_TAUSLOW 1000.0 # Slow pool turnover time [y] +SRESP_FAIR 0.7 # Fraction of respired carbon from litter pool that is lost + # to atmosphere +SRESP_FINTER 0.985 # Fraction of [respired carbon from litter pool that goes + # to soil] that goes to intermediate pool +############################################################################### + +############################################################################### +# Iteration bracket widths +SNOW_DT 5.0 # Used to bracket snow surface temperatures while computing the + # snow surface energy balance (C) +SURF_DT 1.0 # Used to bracket soil surface temperatures while computing + # energy balance (C) +SOIL_DT 0.25 # Used to bracket soil temperatures while solving the soil + # thermal flux (C) +CANOPY_DT 1.0 # Used to bracket canopy air temperatures while computing + #energy balance (C) +CANOPY_VP 25.0 # Used to bracket canopy vapor pressures while computing + # moisture balance (Pa) +############################################################################### + +############################################################################### +# Snow Parameters + +# maximum depth of the surface layer in water equivalent (m) [default 0.125] +SNOW_MAX_SURFACE_SWE 0.125 + +# density of new fallen snow [50] +SNOW_NEW_SNOW_DENSITY 50.0 + +# Density limit used in calculation of destructive metamorphism +SNOW_DENS_DMLIMIT 100.0 # (kg/m^3) + +SNOW_DENS_MAX_CHANGE 0.9 + +# Constants in snow density computation +SNOW_DENS_ETA0 3.6e6 # viscosity of snow at T=0C and density = 0 + # used in calculation of true viscosity (Ns/m2) +SNOW_DENS_C1 0.04 +SNOW_DENS_C2 2.778e-6 +SNOW_DENS_C5 0.08 # constant used in snow viscosity calculation, taken from + # SNTHRM.89 (/C) +SNOW_DENS_C6 0.021 # constant used in snow viscosity calculation, taken from + # SNTHRM.89 (kg/m3) +SNOW_DENS_F 0.6 # internal compaction rate coefficient + +# Minimum SWQ for which the snowpack energy balance is computed independent of +# the soil surface temperature +SNOW_MIN_SWQ_EB_THRES 0.0010 + +# Attenuation coefficients for shortwave in a snowpack. Values and equation +# taken from Patterson and Hamblin, 1988 +SNOW_A1 0.7 +SNOW_A2 0.3 +SNOW_L1 6.0 # (1/m) +SNOW_L2 20.0 # (1/m) + +# Snow albedo curve parameters. Defaults are from Bras p263. Should not be +# changed except for serious problems with snow melt +SNOW_NEW_SNOW_ALB 0.85 +SNOW_ALB_ACCUM_A 0.94 +SNOW_ALB_ACCUM_B 0.58 +SNOW_ALB_THAW_A 0.82 +SNOW_ALB_THAW_B 0.46 + +# Defines the minimum amount of new snow (mm) which will reset the snowpack +# albedo to new snow +SNOW_TRACESNOW 0.03 +############################################################################### + +############################################################################### +# Blowing Snow Parameters +BLOWING_KA 0.0245187 # thermal conductivity of air (W/mK) +BLOWING_CSALT 0.68 # saltation constant m/s +BLOWING_UTHRESH 0.25 # threshold shear velocity m/s +BLOWING_KIN_VIS 1.3e-5 # Kinemativ viscosity of air (m2/s) +BLOWING_MAX_ITER 100 # Max. iterations for numerical integration +BLOWING_K 5 +BLOWING_MACHEPS 1.0e-6 # Accuracy tolerance for numerical integration +BLOWING_SETTLING 0.3 # Particle settling velocity m/s +BLOWING_NUMINCS 10 # Number of prob intervals to solve for wind. +############################################################################### + +############################################################################### +# July average temperature for tree line +TREELINE_TEMPERATURE 10.0 +############################################################################### diff --git a/tests/test_utils.py b/tests/test_utils.py index 641930323..fddd2ac80 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,3 @@ -#!/usr/bin/env python -''' VIC exact restart testing ''' - import os from collections import OrderedDict @@ -8,6 +5,11 @@ import numpy as np import pandas as pd +import glob +import re +import matplotlib.pyplot as plt +import warnings +import seaborn as sns from tonic.models.vic.vic import (VICRuntimeError, default_vic_valgrind_error_code) @@ -120,7 +122,8 @@ def check_returncode(exe, expected=0): return None elif exe.returncode == default_vic_valgrind_error_code: raise VICValgrindError( - 'Valgrind raised an error when running: "{}"'.format(exe.argstring)) + 'Valgrind raised an error when running: \ + "{}"'.format(exe.argstring)) else: raise VICReturnCodeError( 'VIC return code ({0}) did not match expected ({1}) when running ' @@ -181,7 +184,8 @@ def test_classic_driver_no_output_file_nans(fnames): check_for_nans(df) -# TODO: Update tonic version of this function, need to check that subdaily works +# TODO: Update tonic version of this function, +# need to check that subdaily works def read_vic_ascii(filepath, parse_dates=True, datetime_index=None, sep='\t', comment='#', **kwargs): '''Generic reader function for VIC ASCII output with a standard header @@ -202,13 +206,15 @@ def read_vic_ascii(filepath, parse_dates=True, datetime_index=None, sep='\t', raise ValueError('cannot specify both parse_dates and datetime_index') if parse_dates: + # add datetime index time_cols = ['YEAR', 'MONTH', 'DAY'] df.index = pd.to_datetime(df[time_cols]) if 'SEC' in df: - df.index += pd.Series([pd.Timedelta(s, unit='s') for s in df['SEC']], + df.index += pd.Series([pd.Timedelta(s, unit='s') for s in + df['SEC']], index=df.index) time_cols.append('SEC') - df.drop(time_cols, axis=1) + df.drop(time_cols, inplace=True, axis=1) if datetime_index is not None: df.index = datetime_index @@ -242,8 +248,7 @@ def find_global_param_value(gp, param_name): def check_multistream_classic(fnames): ''' - Test the multistream aggregation in the classic driver - ''' + Test the multistream aggregation in the classic driver ''' how_dict = {'OUT_ALBEDO': 'max', 'OUT_SOIL_TEMP_1': 'min', @@ -283,12 +288,14 @@ def check_multistream_classic(fnames): # Loop over all grid cells in result dir for gridcell in gridcells: - fname = os.path.join(resultdir, '{}_{}.txt'.format(inst_stream, gridcell)) + fname = os.path.join(resultdir, + '{}_{}.txt'.format(inst_stream, gridcell)) instant_df = read_vic_ascii(fname) # Loop over all streams for stream, freq in streams.items(): - fname = os.path.join(resultdir, '{}_{}.txt'.format(stream, gridcell)) + fname = os.path.join(resultdir, + '{}_{}.txt'.format(stream, gridcell)) agg_df = read_vic_ascii(fname) # Setup the resample of the instantaneous data @@ -298,7 +305,8 @@ def check_multistream_classic(fnames): for key, how in how_dict.items(): # Get the aggregated values (from VIC) actual = agg_df[key].values - # Calculated the expected values based on the resampling from pandas + # Calculated the expected values based on the resampling from + # pandas expected = rs[key].aggregate(how).values # Compare the actual and expected (with tolerance) @@ -306,3 +314,502 @@ def check_multistream_classic(fnames): actual, expected, decimal=4, err_msg='Variable=%s, freq=%s, how=%s: ' 'failed comparison' % (key, freq, how)) + + +def tsplit(string, delimiters): + '''Behaves like str.split but supports multiple delimiters. ''' + + delimiters = tuple(delimiters) + stack = [string] + + for delimiter in delimiters: + for i, substring in enumerate(stack): + substack = substring.split(delimiter) + stack.pop(i) + for j, _substring in enumerate(substack): + stack.insert(i+j, _substring) + + return stack + + +def read_snotel_swe_obs(filename, science_test_data_dir, items): + '''Reads in Snotel SWE obs and returns DataFrame. ''' + + filename_fullpath = os.path.join(science_test_data_dir, + 'datasets', + items['archive'], + 'observations', + filename) + + # load snotel obs + snotel_swe = pd.read_csv(filename_fullpath, + skiprows=0, + delim_whitespace=True, + names=['YEAR', 'MONTH', 'DAY', 'OUT_SWE']) + + # add datetime index + time_cols = ['YEAR', 'MONTH', 'DAY'] + snotel_swe.index = pd.to_datetime(snotel_swe[time_cols]) + + # remove year, day columns of DataFrame + snotel_swe.drop(time_cols, inplace=True, axis=1) + + return snotel_swe + + +def read_vic_42_output(lat, lng, science_test_data_dir, items): + ''' Reads output from VIC 4.2. ''' + + if items['compare_to'] == 'ecflux': + vic_42_file = 'en_bal_%s_%s' % (lat, lng) + vic_42_dir = os.path.join(science_test_data_dir, 'test_runs', + items['archive'], 'ecflux', 'results') + + elif items['compare_to'] == 'snotel': + vic_42_file = 'outfile_%s_%s' % (lat, lng) + vic_42_dir = os.path.join(science_test_data_dir, 'test_runs', + items['archive'], 'snotel', 'results') + + else: + raise ValueError("this option (%s) has not yet been implemented" + % items['compare_to']) + + vic_42 = pd.read_csv(os.path.join(vic_42_dir, vic_42_file), + sep='\t', + skiprows=5) + + # remove comment sign from column names in DataFrame + vic_42 = vic_42.rename(columns=lambda x: x.replace('#', '')) + + # remove spaces from column names in DataFrame + vic_42 = vic_42.rename(columns=lambda x: x.replace(' ', '')) + + # rename radiation variables to be consistent with VIC 5 + if items['compare_to'] == 'ecflux': + vic_42 = vic_42.rename(columns=lambda x: x.replace('OUT_NET_SHORT', + 'OUT_SWNET')) + vic_42 = vic_42.rename(columns=lambda x: x.replace('OUT_NET_LONG', + 'OUT_LWNET')) + + # add datetime index + time_cols = ['YEAR', 'MONTH', 'DAY'] + vic_42.index = pd.to_datetime(vic_42[time_cols]) + + if 'HOUR' in vic_42: + vic_42.index += pd.Series([pd.Timedelta(s, unit='h') for s in + vic_42['HOUR']], + index=vic_42.index) + time_cols.append('HOUR') + + # remove year, day columns of DataFrame + vic_42.drop(time_cols, inplace=True, axis=1) + + return vic_42 + + +def read_vic_5_output(lat, lng, science_test_data_dir, items): + ''' Read VIC 5.0.x output. ''' + + if items['compare_to'] == 'ecflux': + vic_5_file = 'en_bal_%s_%s.txt' % (lat, lng) + vic_5_dir = os.path.join(science_test_data_dir, 'test_runs', + items['archive'], 'ecflux', 'results') + + elif items['compare_to'] == 'snotel': + vic_5_file = 'outfile_%s_%s.txt' % (lat, lng) + vic_5_dir = os.path.join(science_test_data_dir, 'test_runs', + items['archive'], 'snotel', 'results') + + else: + raise ValueError("this option (%s) has not yet been implemented" + % items['compare_to']) + + vic_5 = pd.read_csv(os.path.join(vic_5_dir, vic_5_file), + skiprows=2, + sep='\t') + + # remove spaces from column names + vic_5.rename(columns=lambda x: x.replace(' ', ''), inplace=True) + + # add datetime index + time_cols = ['YEAR', 'MONTH', 'DAY'] + vic_5.index = pd.to_datetime(vic_5[time_cols]) + + if 'SEC' in vic_5: + vic_5.index += pd.Series([pd.Timedelta(s, unit='s') + for s in vic_5['SEC']], index=vic_5.index) + time_cols.append('SEC') + + # remove year, day columns of DataFrame + vic_5.drop(time_cols, inplace=True, axis=1) + + return vic_5 + + +def plot_science_tests(driver, test_type, science_test_data_dir, result_dir, + plot_dir, plots_to_make, compare_data): + + ''' makes science test figures + + Parameters + ---------- + driver: + Name of Driver + test_type: + Name of test + science_test_data_dir: + Science test data directory + result_dir: + Result directory + plot_dir: + Directory for output plots + plots_to_make + Keys that indicate which plots should be made + compare_data + Keys that indicate which datasets and model output to use for + comparison. + + Returns + ---------- + ''' + if test_type == "science_test_snotel": + plot_snotel_comparison(driver, + science_test_data_dir, + compare_data, + result_dir, + plot_dir, + plots_to_make) + + elif test_type == "science_test_fluxnet": + plot_fluxnet_comparison(driver, + science_test_data_dir, + compare_data, + result_dir, + plot_dir, + plots_to_make) + else: + raise ValueError("this option %s has not been implemented in the \ + VIC 5.0 science test suite" % test_type) + + +def plot_snotel_comparison(driver, science_test_data_dir, + compare_data_dict, + result_dir, plot_dir, + plots_to_make): + ''' makes snotel figures ''' + + # plot settings + plot_variables = {'OUT_SWE': 'mm', 'OUT_ALBEDO': 'fraction', + 'OUT_SALBEDO': 'fraction', 'OUT_SNOW_DEPTH': 'mm', + 'OUT_SNOW_CANOPY': '%', 'OUT_SNOW_PACK_TEMP': + 'degrees C', 'OUT_SNOW_MELT': 'mm', 'OUT_R_NET': + '$W/{m^2}$', 'OUT_LATENT': '$W/{m^2}$', + 'OUT_SENSIBLE': '$W/{m^2}$'} + context = "paper" + style = "whitegrid" + + for filename in os.listdir(os.path.join(science_test_data_dir, + 'datasets', + 'snotel', + 'observations')): + + # get lat/lng from filename + file_split = re.split('_', filename) + lng = file_split[3].split('.txt')[0] + lat = file_split[2] + + # loop over data to compare + data = {} + for key, items in compare_data_dict.items(): + + # read in data + if key == "snotel": + data[key] = read_snotel_swe_obs(filename, + science_test_data_dir, + items) + + elif key == "VIC.4.2.d": + data[key] = read_vic_42_output(lat, lng, + science_test_data_dir, + items) + + else: + data[key] = read_vic_5_output(lat, lng, + science_test_data_dir, + items) + + # loop over variables to plot + for plot_variable, units in plot_variables.items(): + + if 'water_year' in plots_to_make: + + with plt.rc_context(dict(sns.axes_style(style), + **sns.plotting_context(context))): + fig, ax = plt.subplots(figsize=(10, 10)) + + df = pd.DataFrame({key: d[plot_variable] for key, d in + data.items() if plot_variable in d}) + + for key, series in df.iteritems(): + series.plot( + use_index=True, + linewidth=compare_data_dict[key]['linewidth'], + ax=ax, + color=compare_data_dict[key]['color'], + linestyle=compare_data_dict[key] + ['linestyle'], + zorder=compare_data_dict[key]['zorder']) + + ax.legend(loc='upper left') + ax.set_ylabel("%s [%s]" % (plot_variable, units)) + + # save figure + os.makedirs(os.path.join(plot_dir, plot_variable), + exist_ok=True) + plotname = '%s_%s.png' % (lat, lng) + savepath = os.path.join(plot_dir, plot_variable, plotname) + plt.savefig(savepath, bbox_inches='tight') + + plt.clf() + plt.close() + + +def check_site_files(obs_dir, subdir): + return len(os.listdir(os.path.join(obs_dir, subdir))) > 0 + + +def get_fluxnet_lat_lon(obs_dir, subdir): + + # get CSV file from site directory to get lat/lng for site + try: + site_csv_file = glob.glob(os.path.join(obs_dir, subdir, 'AMF*.csv'))[0] + except IndexError: + site_csv_file = glob.glob(os.path.join(obs_dir, subdir, 'us*.csv'))[0] + with open(site_csv_file) as f: + second_line = list(f)[1] + + # parse line from header to get lat/lng + str_split = tsplit(second_line, + ('Latitude: ', 'Longitude: ', 'Elevation (masl): ')) + lat = str_split[1].strip() + lng = str_split[2].strip() + + return lat, lng + + +def read_fluxnet_obs(subdir, science_test_data_dir, items): + + # column names for DataFrame (same as VIC variable names) + fluxnet_names = ['YEAR', 'MONTH', 'DAY', 'HOUR', 'PREC', 'AIR_TEMP', + 'SWDOWN', 'LWDOWN', 'OUT_REL_HUMID', 'PRESSURE', 'WIND', + 'OUT_EVAP', 'SOIL_TEMP_DEPTH1', 'SOIL_TEMP_DEPTH2', + 'SOIL_TEMP_DEPTH3', 'SOIL_TEMP_DEPTH4', + 'SOIL_TEMP_DEPTH5', 'OUT_SOIL_MOIST1', 'OUT_SOIL_MOIST2', 'OUT_SOIL_MOIST3', 'OUT_SOIL_MOIST4', 'OUT_SOIL_MOIST5', + 'OUT_SOIL_TEMP1', 'OUT_SOIL_TEMP2', 'OUT_SOIL_TEMP3', + 'OUT_SOIL_TEMP4', 'OUT_SOIL_TEMP5', 'OUT_SWNET', + 'OUT_LWNET', 'OUT_SENSIBLE', 'OUT_LATENT', + 'OUT_GRND_FLUX'] + + filename = '%s.stdfmt.hourly.local.txt' % subdir + # read in data with -9999.0000 as NaNs + obs_dir = os.path.join(science_test_data_dir, 'datasets', + 'ec_flux_towers', 'obs') + ecflux_df = pd.read_csv(os.path.join(obs_dir, subdir, filename), + skiprows=0, + delim_whitespace=True, + header=None, + names=fluxnet_names, + na_values=-9999.0000) + + # add datetime index + time_cols = ['YEAR', 'MONTH', 'DAY'] + ecflux_df.index = pd.to_datetime(ecflux_df[time_cols]) + + if 'HOUR' in ecflux_df: + ecflux_df.index += pd.Series([pd.Timedelta(s, unit='h') for s in + ecflux_df['HOUR']], + index=ecflux_df.index) + time_cols.append('HOUR') + + # remove year, day columns of DataFrame + ecflux_df.drop(time_cols, inplace=True, axis=1) + + return ecflux_df + + +def plot_fluxnet_comparison(driver, science_test_data_dir, + compare_data_dict, + result_dir, plot_dir, + plots_to_make): + ''' makes Ameriflux figures + ''' + + context = "paper" + style = "whitegrid" + var_names = {'OUT_LATENT': 'LH', 'OUT_SENSIBLE': 'H', 'OUT_SWNET': + 'SW_NET', 'OUT_LWNET': 'LW NET'} + + months = ['January', 'February', 'March', 'April', 'May', + 'June', 'July', 'August', 'September', + 'October', 'November', 'December'] + + # loop over Ameriflux sites + obs_dir = os.path.join(science_test_data_dir, + 'datasets', + 'ec_flux_towers', + 'obs') + + for subdir in os.listdir(obs_dir): + + if check_site_files(obs_dir, subdir): + # get CSV file from site directory to get lat/lng for site + lat, lng = get_fluxnet_lat_lon(obs_dir, subdir) + + # loop over data to compare + data = {} + for key, items in compare_data_dict.items(): + + if key == "ecflux": + try: + # load Ameriflux data + data[key] = read_fluxnet_obs(subdir, + science_test_data_dir, + items) + except OSError: + warnings.warn( + "this %s site does not have data" % subdir) + + elif key == "VIC.4.2.d": + try: + # load VIC 4.2 simulations + data[key] = read_vic_42_output(lat, lng, + science_test_data_dir, + items) + + except OSError: + warnings.warn( + "this site has a lat/lng precision issue") + + else: + try: + # load VIC 5 simulations + data[key] = read_vic_5_output(lat, lng, + science_test_data_dir, + items) + except OSError: + warnings.warn( + "this site has a lat/lng precision issue") + + # make figures + + # plot preferences + fs = 15 + dpi = 150 + + if 'annual_mean_diurnal_cycle' in plots_to_make: + + # make annual mean diurnal cycle plots + with plt.rc_context(dict(sns.axes_style(style), + **sns.plotting_context(context))): + f, axarr = plt.subplots(4, 1, figsize=(8, 8), sharex=True) + + for i, (vic_var, variable_name) in enumerate( + var_names.items()): + + # calculate annual mean diurnal cycle for each + # DataFrame + annual_mean = {} + for key, df in data.items(): + annual_mean[key] = pd.DataFrame( + df[vic_var].groupby(df.index.hour).mean()) + + df = pd.DataFrame( + {key: d[vic_var] for key, d in annual_mean.items() + if vic_var in d}) + + for key, series in df.iteritems(): + series.plot( + linewidth=compare_data_dict[key]['linewidth'], + ax=axarr[i], + color=compare_data_dict[key]['color'], + linestyle=compare_data_dict[key]['linestyle'], + zorder=compare_data_dict[key]['zorder']) + + axarr[i].legend(loc='upper left') + axarr[i].set_ylabel( + '%s ($W/{m^2}$)' % variable_name, + size=fs) + axarr[i].set_xlabel('Time of Day (Hour)', size=fs) + axarr[i].set_xlim([0, 24]) + axarr[i].xaxis.set_ticks(np.arange(0, 24, 3)) + + # save plot + plotname = '%s_%s.png' % (lat, lng) + os.makedirs(os.path.join(plot_dir, 'annual_mean'), + exist_ok=True) + savepath = os.path.join(plot_dir, 'annual_mean', plotname) + plt.savefig(savepath, bbox_inches='tight', dpi=dpi) + + plt.clf() + plt.close() + + if 'monthly_mean_diurnal_cycle' in plots_to_make: + + # make monthly mean diurnal cycle plots + with plt.rc_context(dict(sns.axes_style(style), + **sns.plotting_context(context))): + f, axarr = plt.subplots(4, 12, figsize=(35, 7), + sharex=True, + sharey=True) + + for i, (vic_var, variable_name) in enumerate( + var_names.items()): + + # calculate monthly mean diurnal cycle + monthly_mean = {} + for (key, df) in data.items(): + monthly_mean[key] = pd.DataFrame( + df[vic_var].groupby([df.index.month, + df.index.hour]).mean()) + + df = pd.DataFrame( + {key: d[vic_var] for key, d in monthly_mean.items() + if vic_var in d}) + + for j, month in enumerate(months): + + for key, series in df.iteritems(): + series[j + 1].plot( + linewidth=compare_data_dict[key]['linewidth'], + ax=axarr[i, j], + color=compare_data_dict[key]['color'], + linestyle=compare_data_dict[key]['linestyle'], + zorder=compare_data_dict[key]['zorder']) + + axarr[i, j].set_ylabel( + '%s \n ($W/{m^2}$)' % variable_name, + size=fs) + axarr[i, j].set_xlabel('', size=fs) + axarr[i, j].set_xlim([0, 24]) + axarr[i, j].xaxis.set_ticks(np.arange(0, 24, 3)) + if i == 0: + axarr[i, j].set_title(month, size=fs) + + # add legend + axarr[0, -1].legend(loc='center left', + bbox_to_anchor=(1, 0.5)) + + # add common x label + f.text(0.5, 0.04, 'Time of Day (Hour)', ha='center', + size=fs) + + # save plot + plotname = '%s_%s.png' % (lat, lng) + os.makedirs(os.path.join(plot_dir, 'monthly_mean'), + exist_ok=True) + savepath = os.path.join(plot_dir, + 'monthly_mean', plotname) + plt.savefig(savepath, bbox_inches='tight', dpi=dpi) + + plt.clf() + plt.close() From 737e9a27ac3c34358cde53a94727e6daf7f1008c Mon Sep 17 00:00:00 2001 From: yixinmao Date: Wed, 10 Aug 2016 10:32:23 -0700 Subject: [PATCH 27/33] Fixed bugs related to volumetric heat capacity of water (#574) * Fixed bugs related to volumetric heat capacity of water * Added bug fix notes related to water heat capacity bug fix in `func_canapy_energy_bal.c` * Add PR number in ReleaseNotes bug fix * Minor update of ReleaseNotes --- docs/Development/ReleaseNotes.md | 4 ++++ vic/vic_run/src/IceEnergyBalance.c | 2 +- vic/vic_run/src/SnowPackEnergyBalance.c | 2 +- vic/vic_run/src/func_canopy_energy_bal.c | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/Development/ReleaseNotes.md b/docs/Development/ReleaseNotes.md index 641a70109..f2bbf7bdd 100644 --- a/docs/Development/ReleaseNotes.md +++ b/docs/Development/ReleaseNotes.md @@ -175,6 +175,10 @@ This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly ide Fixed a bug so that the binary format state file I/O works correctly. +5. Fix for a physical constant (water heat capacity) ([GH#574](https://github.com/UW-Hydro/VIC/pull/574)) + + Fixed a bug where volumetric heat capacity of water should be used in `func_canopy_energy_bal` (previously specific heat capacity was used). + ------------------------------ ## VIC 4.2.c [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.35302.svg)](http://dx.doi.org/10.5281/zenodo.35302) diff --git a/vic/vic_run/src/IceEnergyBalance.c b/vic/vic_run/src/IceEnergyBalance.c index 01eb1d0e3..c1b7f63b2 100644 --- a/vic/vic_run/src/IceEnergyBalance.c +++ b/vic/vic_run/src/IceEnergyBalance.c @@ -178,7 +178,7 @@ IceEnergyBalance(double TSurf, /* Calculate advected heat flux from rain */ // Temporary fix for lake model. - *AdvectedEnergy = (CONST_CPFW * Tair * Rain) / Dt; + *AdvectedEnergy = (CONST_CPFW * CONST_RHOFW * Tair * Rain) / Dt; /* Calculate change in cold content */ /* No change in cold content in lake model */ diff --git a/vic/vic_run/src/SnowPackEnergyBalance.c b/vic/vic_run/src/SnowPackEnergyBalance.c index f241ee088..96a96b6e4 100644 --- a/vic/vic_run/src/SnowPackEnergyBalance.c +++ b/vic/vic_run/src/SnowPackEnergyBalance.c @@ -238,7 +238,7 @@ SnowPackEnergyBalance(double TSurf, Equation 7.3.12 from H.B.H. for rain falling on melting snowpack */ if (TMean == 0.) { - *AdvectedEnergy = (CONST_CPFW * (Tair) * Rain) / (Dt); + *AdvectedEnergy = (CONST_CPFW * CONST_RHOFW * (Tair) * Rain) / (Dt); } else { *AdvectedEnergy = 0.; diff --git a/vic/vic_run/src/func_canopy_energy_bal.c b/vic/vic_run/src/func_canopy_energy_bal.c index e16afc55a..5f5a9d066 100644 --- a/vic/vic_run/src/func_canopy_energy_bal.c +++ b/vic/vic_run/src/func_canopy_energy_bal.c @@ -256,7 +256,8 @@ func_canopy_energy_bal(double Tfoliage, /* Calculate the advected energy */ - *AdvectedEnergy = (CONST_CPFW * Tcanopy * Rainfall) / (delta_t); + *AdvectedEnergy = (CONST_CPFW * CONST_RHOFW * Tcanopy * Rainfall) / + (delta_t); /* Calculate the amount of energy available for refreezing */ From c640e71e4413f4b66ee66ffebbd21baaf246d2bb Mon Sep 17 00:00:00 2001 From: Diana Gergel Date: Sat, 13 Aug 2016 10:05:06 -0700 Subject: [PATCH 28/33] updated paths to agree with directory structure of the VIC5_test_data ftp server (#577) --- tests/test_utils.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index fddd2ac80..a2b9ef8cb 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -336,7 +336,8 @@ def read_snotel_swe_obs(filename, science_test_data_dir, items): '''Reads in Snotel SWE obs and returns DataFrame. ''' filename_fullpath = os.path.join(science_test_data_dir, - 'datasets', + 'science', + 'inputdata', items['archive'], 'observations', filename) @@ -362,12 +363,12 @@ def read_vic_42_output(lat, lng, science_test_data_dir, items): if items['compare_to'] == 'ecflux': vic_42_file = 'en_bal_%s_%s' % (lat, lng) - vic_42_dir = os.path.join(science_test_data_dir, 'test_runs', + vic_42_dir = os.path.join(science_test_data_dir, 'science', 'archive', items['archive'], 'ecflux', 'results') elif items['compare_to'] == 'snotel': vic_42_file = 'outfile_%s_%s' % (lat, lng) - vic_42_dir = os.path.join(science_test_data_dir, 'test_runs', + vic_42_dir = os.path.join(science_test_data_dir, 'science', 'archive', items['archive'], 'snotel', 'results') else: @@ -412,12 +413,12 @@ def read_vic_5_output(lat, lng, science_test_data_dir, items): if items['compare_to'] == 'ecflux': vic_5_file = 'en_bal_%s_%s.txt' % (lat, lng) - vic_5_dir = os.path.join(science_test_data_dir, 'test_runs', + vic_5_dir = os.path.join(science_test_data_dir, 'science', 'archive', items['archive'], 'ecflux', 'results') elif items['compare_to'] == 'snotel': vic_5_file = 'outfile_%s_%s.txt' % (lat, lng) - vic_5_dir = os.path.join(science_test_data_dir, 'test_runs', + vic_5_dir = os.path.join(science_test_data_dir, 'science', 'archive', items['archive'], 'snotel', 'results') else: @@ -509,7 +510,8 @@ def plot_snotel_comparison(driver, science_test_data_dir, style = "whitegrid" for filename in os.listdir(os.path.join(science_test_data_dir, - 'datasets', + 'science', + 'inputdata', 'snotel', 'observations')): @@ -604,7 +606,8 @@ def read_fluxnet_obs(subdir, science_test_data_dir, items): 'SWDOWN', 'LWDOWN', 'OUT_REL_HUMID', 'PRESSURE', 'WIND', 'OUT_EVAP', 'SOIL_TEMP_DEPTH1', 'SOIL_TEMP_DEPTH2', 'SOIL_TEMP_DEPTH3', 'SOIL_TEMP_DEPTH4', - 'SOIL_TEMP_DEPTH5', 'OUT_SOIL_MOIST1', 'OUT_SOIL_MOIST2', 'OUT_SOIL_MOIST3', 'OUT_SOIL_MOIST4', 'OUT_SOIL_MOIST5', + 'SOIL_TEMP_DEPTH5', 'OUT_SOIL_MOIST1', 'OUT_SOIL_MOIST2', + 'OUT_SOIL_MOIST3', 'OUT_SOIL_MOIST4', 'OUT_SOIL_MOIST5', 'OUT_SOIL_TEMP1', 'OUT_SOIL_TEMP2', 'OUT_SOIL_TEMP3', 'OUT_SOIL_TEMP4', 'OUT_SOIL_TEMP5', 'OUT_SWNET', 'OUT_LWNET', 'OUT_SENSIBLE', 'OUT_LATENT', @@ -612,7 +615,7 @@ def read_fluxnet_obs(subdir, science_test_data_dir, items): filename = '%s.stdfmt.hourly.local.txt' % subdir # read in data with -9999.0000 as NaNs - obs_dir = os.path.join(science_test_data_dir, 'datasets', + obs_dir = os.path.join(science_test_data_dir, 'science', 'inputdata', 'ec_flux_towers', 'obs') ecflux_df = pd.read_csv(os.path.join(obs_dir, subdir, filename), skiprows=0, @@ -641,8 +644,7 @@ def plot_fluxnet_comparison(driver, science_test_data_dir, compare_data_dict, result_dir, plot_dir, plots_to_make): - ''' makes Ameriflux figures - ''' + ''' makes Ameriflux figures ''' context = "paper" style = "whitegrid" @@ -655,7 +657,8 @@ def plot_fluxnet_comparison(driver, science_test_data_dir, # loop over Ameriflux sites obs_dir = os.path.join(science_test_data_dir, - 'datasets', + 'science', + 'inputdata', 'ec_flux_towers', 'obs') From 0cac5f2a4e36009f273b84e275fe8f061c62c74c Mon Sep 17 00:00:00 2001 From: yixinmao Date: Wed, 17 Aug 2016 20:09:34 -0700 Subject: [PATCH 29/33] Add test drivers match (#576) * Add mpi multiprocessing test - test whether the flux and state results using different number of processors are exactly identical for image driver * Add instruction on running VIC image driver using multiple processors to the documentation * Add cross-driver comparison test - half-way finished * Turn on SNOW_BAND in cross-driver testing global param template file * Fixed bugs related to ice heat capacity - In vic_run code, fixed bugs that confused volumetric heat capacity and specific heat capacity related to ice * Combine the volumetric ice heat capacity (per volume of water equivalent) into a single constant * Finished driver comparison test * Fixed a bug in run_tests.py * Made system_tests.cfg consistent with develop branch * Minor formatting * Fixed a bug so that both single- and multi-driver tests are compatible with system, science and example tests * Fixed a bug in run_tests.py to be compatible with science tests * Clean up test code - mostly related to handling cross-driver tests * Removed an unused domain file from test directory * Test code clean up; remove unused domain file under test/example * Update travis build for classic driver and image driver * Fixed a bug when calling run_example * Fixed a bug related to drop_tests --- ci/classic.travis | 4 +- ci/image.travis | 4 +- tests/examples/domain.stehekin.20151028.nc | Bin 4160 -> 0 bytes tests/run_tests.py | 247 +++++++++++++++------ tests/system/global.image.STEHE.txt | 11 +- tests/system/system_tests.cfg | 11 + tests/test_image_driver.py | 25 ++- tests/test_restart.py | 19 +- tests/test_utils.py | 203 ++++++++++++++++- 9 files changed, 426 insertions(+), 98 deletions(-) delete mode 100644 tests/examples/domain.stehekin.20151028.nc diff --git a/ci/classic.travis b/ci/classic.travis index cea2dd5be..09295358d 100644 --- a/ci/classic.travis +++ b/ci/classic.travis @@ -57,10 +57,8 @@ function vic_script { # Run test package ./tests/run_tests.py unit examples system \ - --vic_exe=${DRIVER_EXE} \ - --driver=${TESTID} \ + --classic=${DRIVER_EXE} \ --data_dir=${SAMPLES_PATH}/data - } function vic_after_success { diff --git a/ci/image.travis b/ci/image.travis index c37f31411..c0d022fe2 100644 --- a/ci/image.travis +++ b/ci/image.travis @@ -83,10 +83,8 @@ function vic_script { # Run test package ./tests/run_tests.py unit examples system \ - --vic_exe=${DRIVER_EXE} \ - --driver=${TESTID} \ + --image=${DRIVER_EXE} \ --data_dir=${SAMPLES_PATH}/data - } function vic_after_success { diff --git a/tests/examples/domain.stehekin.20151028.nc b/tests/examples/domain.stehekin.20151028.nc deleted file mode 100644 index 5d8f1fa3702279333a41caaf02b258b19a9fdf3f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4160 zcmeHKO=u)V6rN2cKgLAYJ?ILGMO>ByX1b>*KgNmcBuFyf3 zYm$v#j6W9_1s9bCWegs~)pNj;24MveFXB;fJ$YL6AcBI4?^SoFXU0h~%Hqj_>aTuY zy?XD}tM{r4bMwa%K^Xw(g4%6Ufg?%T<}S8-pbkPsn(o5fB7mgL7i`O+f{{5YC|Ps` z^GeiUWQ}>g#a*H)lgh(nq#{H$r>aiXa+pw@YFROvYM9n2^0~dh-8JS4p!Xxby@mO- zrc7Wr(O0p2!M%-euB*O61$lycBs)p8Y;HW8%S@7NMw`qL*PzubN&Cd1{^}Xa6(iUf zB_?;M}4x1ZzhM8p95F|TAG%c5z%1y|fCUV3uIq{f7s|I&d zDQTqn+w9@3S%z|pWO*nzHjY|@ETFXzAZdD;q$%-v%`;f4Z1W6TQJH$PV7AyW5|E zoKHSJH+vRZNcRA?Nmj`ynH2b!&8QFN!(&!6ld3k33%ZvI%ZNzdKRm8XC}YFeKj|7= z=T+u9Rb5oT@}}yWu6nt5l&TDRJB8>y}$4!{I)|1l-fJiZ#J<9Xpf39S34U3R$NpIB|xoQM<;7 z<(d}wJM)RbY@1jdD+}8>n?Q~7zS5PMx>*7 zj>Q)m!x&uWH4J9!73MJ+$sPs2kVP8}LYy{DnC&x35sYM}<6Sg7l*SWkqsIYz$^eRC zBUq2ECT7U`aBdADNm>|L$dhcgaLBo1Ua^HGLyT|O!01MJiIhFd3_L?rAWeXKG`dD7 zn|Tb+4^96VbxlojZ!*H+q6Ya#EzuHd1O2&$S_*q)s2y6E-9iY z3K=~_qBggc0=IvCTVr>L?SvOmN3JRS1QLdu93mNJP&}=8O=yiy88oN8|9#Aapdc?h z+VR%=7-SB32MUaivMKY=@u$u$7QzHfOn3vr6ub}j^V3Yz`*69+JPJ=azr*(-58j8k zFVrN)BtXo2STL92n-u2;^m)s+&tZmuUYzf+-52H(Y~$Kfoum?=yKO(z;L2d_{>$UA zSkn;kaovz(`935>T_!LbNhErqqWn=wqWeMz3F3sWI3NQ^%Dua`D2LMOjnKfQ%`t?#!V_V)ImDGSc) z(9i$8`0M);;e+_oyEkTlB7ePpdI#~l=YO0*`~^OZc=PPE?0>SfxrL3eMZ_=FuLxjNX6xJMOPhc01i1T|#Fvuq1^vCx!|{)2>mQ6f`2CekfN#DQ;MKhV z-x>?&)3fzAZm#sdej>ojR|CBAVL09uj&IM_U-;;co>%V)@a1;`yu2IWE8m8=`xjn< BXW0M% diff --git a/tests/run_tests.py b/tests/run_tests.py index afbddaa5b..d5a240114 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -16,14 +16,17 @@ from tonic.models.vic.vic import VIC, default_vic_valgrind_suppressions_path from tonic.io import read_config, read_configobj from tonic.testing import VICTestError -from test_utils import (setup_test_dirs, print_test_dict, - replace_global_values, drop_tests, pop_run_kwargs, - check_returncode, process_error, - test_classic_driver_all_complete, - test_classic_driver_no_output_file_nans, - find_global_param_value, - check_multistream_classic, - plot_science_tests) +from test_utils import ( + setup_test_dirs, print_test_dict, + replace_global_values, drop_tests, pop_run_kwargs, + check_returncode, process_error, + test_classic_driver_all_complete, + test_classic_driver_no_output_file_nans, + find_global_param_value, + check_multistream_classic, + setup_subdirs_and_fill_in_global_param_driver_match_test, + check_drivers_match_fluxes, + plot_science_tests) from test_image_driver import (test_image_driver_no_output_file_nans, check_multistream_image, setup_subdirs_and_fill_in_global_param_mpi_test, @@ -125,7 +128,8 @@ def main(): default=['unit', 'system'], nargs='+') parser.add_argument('--system', type=str, help='system tests configuration file', - default=os.path.join(test_dir, 'system/system_tests.cfg')) + default=os.path.join(test_dir, + 'system/system_tests.cfg')) parser.add_argument('--science', type=str, help='science tests configuration file', default=os.path.join(test_dir, 'science/science.cfg')) @@ -135,14 +139,10 @@ def main(): parser.add_argument('--release', type=str, help='release tests configuration file', default=os.path.join(test_dir, 'release/release.cfg')) - parser.add_argument('--vic_exe', type=str, - help='VIC executable to test', - default=os.path.join( - test_dir, '../vic/drivers/classic/vic_classic.exe')) - parser.add_argument('--driver', type=str, - help='VIC driver to test', - choices=['classic', 'image'], - default='classic') + parser.add_argument('--classic', type=str, + help='classic driver executable to test') + parser.add_argument('--image', type=str, + help='image driver executable to test') parser.add_argument('--output_dir', type=str, help='directory to write test output to', default='$WORKDIR/VIC_tests_{0}'.format(ymd)) @@ -177,9 +177,17 @@ def main(): print('Running Test Set: {0}'.format(', '.join(args.tests))) # Setup VIC executable + # --- if not only unit test --- # if not (len(args.tests) == 1 and args.tests[0] == 'unit'): - vic_exe = VIC(args.vic_exe) - print('VIC version information:\n\n{0}'.format(vic_exe.version.decode())) + dict_drivers = {} + if args.classic: + dict_drivers['classic'] = VIC(args.classic) + print('VIC classic version information:\n\n{0}'.format( + dict_drivers['classic'].version.decode())) + if args.image: + dict_drivers['image'] = VIC(args.image) + print('VIC image version information:\n\n{0}'.format( + dict_drivers['image'].version.decode())) # run test sets # unit @@ -188,23 +196,31 @@ def main(): # system if any(i in ['all', 'system'] for i in args.tests): - test_results['system'] = run_system(args.system, vic_exe, data_dir, - os.path.join(out_dir, 'system'), - args.driver) + test_results['system'] = run_system(args.system, dict_drivers, + data_dir, + os.path.join(out_dir, + 'system')) + # science if any(i in ['all', 'science'] for i in args.tests): - test_results['science'] = run_science(args.science, vic_exe, - science_test_data_dir, - data_dir, - os.path.join(out_dir, 'science'), - args.driver) + test_results['science'] = run_science( + args.science, dict_drivers['classic'], + science_test_data_dir, + data_dir, + os.path.join(out_dir, 'science'), + 'classic') # examples if any(i in ['all', 'examples'] for i in args.tests): - test_results['examples'] = run_examples(args.examples, vic_exe, - data_dir, - os.path.join( - out_dir, 'examples'), - args.driver) + if len(dict_drivers) == 1: # if only one driver + driver = list(dict_drivers.keys())[0] + vic_exe = dict_drivers[driver] + test_results['examples'] = run_examples(args.examples, vic_exe, + data_dir, + os.path.join( + out_dir, 'examples'), + driver) + else: + raise ValueError('example test only supports single driver') # release if any(i in ['all', 'release'] for i in args.tests): test_results['release'] = run_release(args.release) @@ -280,21 +296,20 @@ def run_unit_tests(test_dir): print('-'.ljust(OUTPUT_WIDTH, '-')) -def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): +def run_system(config_file, dict_drivers, test_data_dir, out_dir): '''Run system tests from config file Parameters ---------- config_file : str Configuration file for system tests. - vic_exe : VIC (object) - VIC executable object (see tonic documentation). + dict_drivers : dict + Keys: driver names {'classic', 'image'} + Content: corresponding VIC executable object (see tonic documentation) test_data_dir : str Path to test data sets. out_dir : str Path to output location - driver : {'classic', 'image'} - Driver to run tests on. Returns ------- @@ -317,8 +332,16 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): # Get setup config = read_configobj(config_file) - # drop invalid driver tests - config = drop_tests(config, driver) + # Process driver info + if len(dict_drivers) == 1: # if single driver + driver = list(dict_drivers.keys())[0] + vic_exe = dict_drivers[driver] + + # Drop invalid driver tests + if len(dict_drivers) == 1: # if single driver + config = drop_tests(config, driver) + else: # if multiple drivers + config = drop_tests(config, list(dict_drivers)) test_results = OrderedDict() @@ -334,38 +357,56 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): mkdirs=['results', 'state', 'logs', 'plots']) # read template global parameter file - infile = os.path.join(test_dir, 'system', - test_dict['global_parameter_file']) - - with open(infile, 'r') as global_file: - global_param = global_file.read() + dict_global_param = {} + # --- if single driver --- # + if len(dict_drivers) == 1: + infile = os.path.join(test_dir, 'system', + test_dict['global_parameter_file']) + with open(infile, 'r') as global_file: + dict_global_param[driver] = global_file.read() + # --- if multiple drivers --- # + else: + for j, dr in enumerate(test_dict['driver']): + infile = os.path.join(test_dir, 'system', + test_dict['global_parameter_file'][j]) + with open(infile, 'r') as global_file: + dict_global_param[dr] = global_file.read() # If restart test, prepare running periods - # (1) Find STATESEC option (and STATE_FORMAT option for later use) - statesec = find_global_param_value(global_param, 'STATESEC') - if driver == 'classic': - state_format = find_global_param_value(global_param, - 'STATE_FORMAT') - # (2) Prepare running periods and initial state file info for restart - # test if 'exact_restart' in test_dict['check']: + if len(dict_drivers) > 1: + raise ValueError('Only support single driver for restart' + 'tests!') + global_param = dict_global_param[driver] + # (1) Find STATESEC option (and STATE_FORMAT option for later use) + statesec = find_global_param_value(global_param, 'STATESEC') + if driver == 'classic': + state_format = find_global_param_value(global_param, + 'STATE_FORMAT') + # (2) Prepare running periods and initial state file info for + # restart test run_periods = prepare_restart_run_periods( test_dict['restart'], dirs['state'], statesec) # If mpi test, prepare a list of number of processors to be run elif 'mpi' in test_dict['check']: + if len(dict_drivers) > 1: + raise ValueError('Only support single driver for MPI' + 'tests!') if not isinstance(test_dict['mpi']['n_proc'], list): - print('Error: need at least two values in n_proc to run' - 'mpi test!') - raise + raise ValueError('Need at least two values in n_proc to run' + 'mpi test!') list_n_proc = test_dict['mpi']['n_proc'] # create template string - s = string.Template(global_param) + dict_s = {} + for dr, global_param in dict_global_param.items(): + dict_s[dr] = string.Template(global_param) # fill in global parameter options # --- if restart test, multiple runs --- # if 'exact_restart' in test_dict['check']: + s = dict_s[driver] # Set up subdirectories and fill in global parameter options # for restart testing list_global_param =\ @@ -374,14 +415,26 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): test_data_dir) # --- if mpi test, multiple runs --- # elif 'mpi' in test_dict['check']: + s = dict_s[driver] # Set up subdirectories and output directories in global file for # multiprocessor testing list_global_param = \ setup_subdirs_and_fill_in_global_param_mpi_test( s, list_n_proc, dirs['results'], dirs['state'], test_data_dir) + # --- if driver-match test, one run for each driver --- # + elif 'driver_match' in test_dict['check']: + # Set up subdirectories and output directories in global file for + # driver-match testing + dict_global_param = \ + setup_subdirs_and_fill_in_global_param_driver_match_test( + dict_s, dirs['results'], dirs['state'], test_data_dir) # --- else, single run --- # else: + if len(dict_drivers) > 1: + raise RuntimeError('Only support single driver for test' + '{}!'.format(testname)) + s = dict_s[driver] global_param = s.safe_substitute(test_data_dir=test_data_dir, result_dir=dirs['results'], state_dir=dirs['state']) @@ -392,11 +445,14 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): replacements = test_dict['options'] else: replacements = OrderedDict() - # --- if STATE_FORMAT is specified, then the specified value (instead - # of the one in the global template file) --- # - if 'STATE_FORMAT' in replacements: - state_format = replacements['STATE_FORMAT'] # --- replace global options --- # + # For the purpose of exact restart, if STATE_FORMAT is specified, + # then record the specified value (instead of the one in the global + # template file) + if 'exact_restart' in test_dict['check']: + if 'STATE_FORMAT' in replacements: + state_format = replacements['STATE_FORMAT'] + if 'exact_restart' in test_dict['check'] or\ 'mpi' in test_dict['check']: # if multiple runs for j, gp in enumerate(list_global_param): @@ -405,6 +461,15 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): # replace global options for this global file list_global_param[j] = replace_global_values(gp, replacements) replacements = replacements_cp + elif 'driver_match' in test_dict['check']: # if cross-driver runs + for dr, gp in dict_global_param.items(): + # save a copy of replacements for the next global file + replacements_cp = replacements.copy() + # replace global options for this global file + dict_global_param[dr] = replace_global_values( + gp, + replacements) + replacements = replacements_cp else: # if single run global_param = replace_global_values(global_param, replacements) @@ -433,6 +498,17 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): with open(test_global_file, mode='w') as f: for line in gp: f.write(line) + elif 'driver_match' in test_dict['check']: + dict_test_global_file = {} + for dr, gp in dict_global_param.items(): + test_global_file = os.path.join( + dirs['test'], + '{}_globalparam_{}.txt'.format( + testname, dr)) + dict_test_global_file[dr] = test_global_file + with open(test_global_file, mode='w') as f: + for line in gp: + f.write(line) else: test_global_file = os.path.join( dirs['test'], @@ -459,7 +535,7 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): # Check return code check_returncode(vic_exe, test_dict.pop('expected_retval', 0)) - if 'mpi' in test_dict['check']: + elif 'mpi' in test_dict['check']: for j, test_global_file in enumerate(list_test_global_file): # Overwrite mpi_proc in option kwargs n_proc = list_n_proc[j] @@ -474,6 +550,25 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): # Check return code check_returncode(vic_exe, test_dict.pop('expected_retval', 0)) + elif 'driver_match' in test_dict['check']: + for dr in dict_test_global_file.keys(): + # Reset mpi_proc in option kwargs to None for classic + # driver run + if dr == 'classic': + run_kwargs_classic = run_kwargs + run_kwargs_classic['mpi_proc'] = None + returncode = dict_drivers[dr].run( + dict_test_global_file[dr], + logdir=dirs['logs'], + **run_kwargs_classic) + else: + returncode = dict_drivers[dr].run( + dict_test_global_file[dr], + logdir=dirs['logs'], + **run_kwargs) + # Check return code + check_returncode(dict_drivers[dr], + test_dict.pop('expected_retval', 0)) else: returncode = vic_exe.run(test_global_file, logdir=dirs['logs'], **run_kwargs) @@ -488,20 +583,31 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): # Check that the simulation completed for all grid cells if 'complete' in test_dict['check']: + if len(dict_drivers) > 1: + raise RuntimeError('Only support single driver for ' + 'complete check') fnames = glob.glob(os.path.join(dirs['results'], '*')) if driver == 'classic': test_classic_driver_all_complete(fnames) + else: + raise RuntimeError('complete check only supports ' + 'classic driver') # check for nans in all example files if 'output_file_nans' in test_dict['check']: + if len(dict_drivers) > 1: + raise RuntimeError('Only support single driver for ' + 'output_file_nans check') fnames = glob.glob(os.path.join(dirs['results'], '*')) if driver == 'classic': test_classic_driver_no_output_file_nans(fnames) elif driver == 'image': - domain_file = os.path.join(test_data_dir, - test_dict['domain_file']) - test_image_driver_no_output_file_nans(fnames, - domain_file) + domain_file = os.path.join( + test_data_dir, + test_dict['domain_file']) + test_image_driver_no_output_file_nans( + fnames, + domain_file) else: raise ValueError('unknown driver') @@ -516,9 +622,14 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): elif driver == 'image': check_exact_restart_states(dirs['state'], driver, run_periods, statesec) + else: + raise ValueError('unknown driver') # check for multistream output if 'multistream' in test_dict['check']: + if len(dict_drivers) > 1: + raise ValueError('Only support single driver for ' + 'multistream check') fnames = glob.glob(os.path.join(dirs['results'], '*')) if driver == 'classic': check_multistream_classic(fnames) @@ -531,12 +642,18 @@ def run_system(config_file, vic_exe, test_data_dir, out_dir, driver): check_mpi_fluxes(dirs['results'], list_n_proc) check_mpi_states(dirs['state'], list_n_proc) + # check that results from different drivers match + if 'driver_match' in test_dict['check']: + check_drivers_match_fluxes(list(dict_drivers.keys()), + dirs['results']) + # if we got this far, the test passed. test_passed = True # Handle errors except Exception as e: - test_comment, error_message = process_error(e, vic_exe) + for dr, exe in dict_drivers.items(): + test_comment, error_message = process_error(e, exe) # record the test results test_results[testname] = TestResults(testname, diff --git a/tests/system/global.image.STEHE.txt b/tests/system/global.image.STEHE.txt index ca376639c..b50e1978b 100644 --- a/tests/system/global.image.STEHE.txt +++ b/tests/system/global.image.STEHE.txt @@ -13,7 +13,12 @@ CALENDAR PROLEPTIC_GREGORIAN FULL_ENERGY TRUE FROZEN_SOIL FALSE -AERO_RESIST_CANSNOW AR_406 +#INIT_STATE +STATENAME $state_dir/states +STATEYEAR 1949 +STATEMONTH 1 +STATEDAY 10 +STATESEC 82800 DOMAIN $test_data_dir/image/Stehekin/parameters/domain.stehekin.20151028.nc DOMAIN_TYPE LAT lat @@ -35,7 +40,11 @@ FORCE_TYPE WIND wind WIND_H 10.0 PARAMETERS $test_data_dir/image/Stehekin/parameters/Stehekin_test_params_20160327.nc +SNOW_BAND TRUE NODES 3 +BASEFLOW ARNO +JULY_TAVG_SUPPLIED FALSE +ORGANIC_FRACT FALSE RESULT_DIR $result_dir/ diff --git a/tests/system/system_tests.cfg b/tests/system/system_tests.cfg index 5927c81cb..a03d8a7c7 100644 --- a/tests/system/system_tests.cfg +++ b/tests/system/system_tests.cfg @@ -236,3 +236,14 @@ check = mpi # A list of number of processors to run and compare (need at least a list of two numbers) n_proc = 1,4 +[System-drivers_match] +test_description = Test whether classic driver and image driver produce similar results +driver = classic,image +# A list of global parameter template files; in the order corresponding to "driver" specified above +global_parameter_file = global.classic.STEHE.txt,global.image.STEHE.txt +expected_retval = 0 +check = driver_match +[[options]] +FULL_ENERGY=FALSE +FROZEN_SOIL=FALSE + diff --git a/tests/test_image_driver.py b/tests/test_image_driver.py index 13b04c6a6..af8746b84 100644 --- a/tests/test_image_driver.py +++ b/tests/test_image_driver.py @@ -8,6 +8,7 @@ import numpy as np import numpy.testing as npt import glob +import warnings def test_image_driver_no_output_file_nans(fnames, domain_file): @@ -204,6 +205,7 @@ def check_mpi_fluxes(result_basedir, list_n_proc): os glob numpy + warnings ''' # Read the first run - as base @@ -212,8 +214,8 @@ def check_mpi_fluxes(result_basedir, list_n_proc): result_basedir, 'processors_{}'.format(n_proc)) if len(glob.glob(os.path.join(result_dir, '*.nc'))) > 1: - print( - 'Warning: more than one netCDF file found under directory {}'. + warnings.warn( + 'More than one netCDF file found under directory {}'. format(result_dir)) fname = glob.glob(os.path.join(result_dir, '*.nc'))[0] ds_first_run = xr.open_dataset(fname) @@ -228,9 +230,9 @@ def check_mpi_fluxes(result_basedir, list_n_proc): result_basedir, 'processors_{}'.format(n_proc)) if len(glob.glob(os.path.join(result_dir, '*.nc'))) > 1: - print( - 'Warning: more than one netCDF file found under directory {}'. - format(result_dir)) + warnings.warn( + 'More than one netCDF file found under directory {}'. + format(result_dir)) fname = glob.glob(os.path.join(result_dir, '*.nc'))[0] ds_current_run = xr.open_dataset(fname) # Compare current run with base run @@ -258,6 +260,7 @@ def check_mpi_states(state_basedir, list_n_proc): os glob numpy + warnings ''' # Read the first run - as base @@ -266,9 +269,9 @@ def check_mpi_states(state_basedir, list_n_proc): state_basedir, 'processors_{}'.format(n_proc)) if len(glob.glob(os.path.join(state_dir, '*.nc'))) > 1: - print( - 'Warning: more than one netCDF file found under directory {}'. - format(state_dir)) + warnings.warn( + 'More than one netCDF file found under directory {}'. + format(state_dir)) fname = glob.glob(os.path.join(state_dir, '*.nc'))[0] ds_first_run = xr.open_dataset(fname) @@ -282,9 +285,9 @@ def check_mpi_states(state_basedir, list_n_proc): state_basedir, 'processors_{}'.format(n_proc)) if len(glob.glob(os.path.join(state_dir, '*.nc'))) > 1: - print( - 'Warning: more than one netCDF file found under directory {}'. - format(result_dir)) + warnings.warn( + 'More than one netCDF file found under directory {}'. + format(result_dir)) fname = glob.glob(os.path.join(state_dir, '*.nc'))[0] ds_current_run = xr.open_dataset(fname) # Compare current run with base run diff --git a/tests/test_restart.py b/tests/test_restart.py index 7501ce825..dbf13a715 100644 --- a/tests/test_restart.py +++ b/tests/test_restart.py @@ -6,6 +6,7 @@ import os import glob import xarray as xr +import warnings from test_utils import read_vic_ascii from tonic.testing import VICTestError @@ -212,6 +213,14 @@ def check_exact_restart_fluxes(result_basedir, driver, run_periods): run_periods: A list of running periods. Return from prepare_restart_run_periods() + Require: + ---------- + xarray + glob + os + numpy + warnings + read_vic_ascii ''' # --- Extract full run period --- # @@ -231,9 +240,9 @@ def check_exact_restart_fluxes(result_basedir, driver, run_periods): dict_df_full_run[os.path.basename(fname)] = df elif driver == 'image': if len(glob.glob(os.path.join(result_dir, '*.nc'))) > 1: - print( - 'Warning: more than one netCDF file found under directory {}'. - format(result_dir)) + warnings.warn( + 'More than one netCDF file found under directory {}'. + format(result_dir)) fname = glob.glob(os.path.join(result_dir, '*.nc'))[0] ds_full_run = xr.open_dataset(fname) @@ -266,8 +275,8 @@ def check_exact_restart_fluxes(result_basedir, driver, run_periods): elif driver == 'image': # Read in flux data if len(glob.glob(os.path.join(result_dir, '*.nc'))) > 1: - print('Warning: more than one netCDF file found under' - 'directory {}'.format(result_dir)) + warnings.warn('More than one netCDF file found under' + 'directory {}'.format(result_dir)) fname = glob.glob(os.path.join(result_dir, '*.nc'))[0] ds = xr.open_dataset(fname) # Extract the same period from the full run diff --git a/tests/test_utils.py b/tests/test_utils.py index a2b9ef8cb..6e71863b2 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,10 +1,12 @@ import os -from collections import OrderedDict +from collections import OrderedDict, namedtuple +import glob import traceback import numpy as np import pandas as pd +import xarray as xr import glob import re import matplotlib.pyplot as plt @@ -18,6 +20,8 @@ OUTPUT_WIDTH = 100 ERROR_TAIL = 20 # lines +VICOutFile = namedtuple('vic_out_file', + ('dirpath', 'prefix', 'lat', 'lon', 'suffix')) class VICReturnCodeError(Exception): pass @@ -97,15 +101,35 @@ def replace_global_values(gp, replace): def drop_tests(config, driver): - '''helper function to remove tests that should not be run for driver''' - new = {} - for key, test_cfg in config.items(): - try: - if test_cfg['driver'].lower() == driver.lower(): - new[key] = test_cfg - except KeyError: - raise KeyError('test configuration must specify driver') - return new + '''helper function to remove tests that should not be run for driver''' + + new = {} + + if not isinstance(driver, list): # if single driver + for key, test_cfg in config.items(): + try: + if not isinstance(test_cfg['driver'], list): + if test_cfg['driver'].lower() == driver.lower(): + new[key] = test_cfg + except KeyError: + raise KeyError('test configuration must specify driver') + else: # if multiple drivers + for key, test_cfg in config.items(): + try: + if isinstance(test_cfg['driver'], list): + # check whether the test has the same number of drivers + if len(test_cfg['driver']) == len(driver): + # check whether the test wants to test the same drivers + flag = 1 + for d in driver: + if d not in test_cfg['driver']: + flag = 0 + if flag == 1: + new[key] = test_cfg + except KeyError: + raise KeyError('test configuration must specify driver') + + return new def pop_run_kwargs(config): @@ -316,6 +340,165 @@ def check_multistream_classic(fnames): 'failed comparison' % (key, freq, how)) +def setup_subdirs_and_fill_in_global_param_driver_match_test( + dict_s, result_basedir, state_basedir, test_data_dir): + ''' Fill in global parameter output directories for multiple driver runs + for driver-match testing + + Parameters + ---------- + dict_s: + A dict of template of the global param file to be filled in + Keys: driver name + result_basedir: + Base directory of output fluxes results; runs with different number of + processors are output to subdirectories under the base directory + state_basedir: + Base directory of output state results; runs with different number of + processors are output to subdirectories under the base directory + test_data_dir: + Base directory of test data + + Returns + ---------- + dict_global_param: + A dict of global parameter strings to be run with parameters filled in + + Require + ---------- + os + ''' + + dict_global_param = {} + for driver in dict_s.keys(): + # Set up subdirectories for results and states + result_dir = os.path.join(result_basedir, driver) + state_dir = os.path.join(state_basedir, driver) + os.makedirs(result_dir, exist_ok=True) + os.makedirs(state_dir, exist_ok=True) + + # Fill in global parameter options + s = dict_s[driver] + dict_global_param[driver] = s.safe_substitute( + test_data_dir=test_data_dir, + result_dir=result_dir, + state_dir=state_dir) + + return(dict_global_param) + + +def parse_classic_driver_outfile_name(fname): + '''helper function to parse VIC classic driver output file name''' + resultdir, filename = os.path.split(fname) + prefix, suffix = os.path.splitext(filename) + pieces = prefix.split('_') + lat, lon = map(float, pieces[-2:]) + return VICOutFile(resultdir, prefix, lat, lon, suffix) + + +def check_drivers_match_fluxes(list_drivers, result_basedir): + ''' Check whether the flux results are similar cross multiple drivers + + Parameters + ---------- + list_drivers: + A list of driver names to be compared + e.g., ['classic'; 'image'] + NOTE: must have classic driver; classic driver will be the base for + comparison + result_basedir: + Base directory of output fluxes results; results for drivers are + subdirectories under the base directory + + Require + ---------- + glob + xarray + numpy + warnings + collections.namedtuple + parse_classic_driver_outfile_name + VICOutFile + read_vic_ascii + ''' + + # Identify all classic driver output flux files + try: + list_fnames_classic = glob.glob(os.path.join( + result_basedir, 'classic', '*')) + except: + raise ValueError('incorrect classic driver output for driver-match ' + 'test') + + # Loop over all other drivers and compare with classic driver + for driver in list_drivers: + # skip classic driver + if driver == 'classic': + continue + # if image driver + if driver == 'image': + # load flux file + if len(glob.glob(os.path.join( + result_basedir, driver, '*.nc'))) > 1: + warnings.warn('More than one netCDF file found under' + 'directory {}'.format(result_dir)) + fname = glob.glob(os.path.join(result_basedir, driver, '*.nc'))[0] + ds_image = xr.open_dataset(fname) + + # loop over each grid cell from classic driver + for fname in list_fnames_classic: + gcell = parse_classic_driver_outfile_name(fname) + df_classic = read_vic_ascii(fname) + ds_image_cell = ds_image.sel(lat=gcell.lat, lon=gcell.lon, + method='nearest') + # compare each variable + for var in ds_image_cell.data_vars: + # if one [time] dimension + if len(ds_image_cell[var].coords) == 3: + # determine precision for comparison + # --- if all zeros for this variable, set + # --- decimal = 2 --- # + if np.sum(np.absolute(ds_image_cell[var].values)) == 0: + decimal = 2 + # --- if not all zeros, set decimal depending on the + # maximum aboslute value of this variable so that the + # comparison has a reasonable precision. Specifically, + # decimal ~= - log10(max_abs_value) + 1 --- # + else: + decimal = int(round(- np.log10(np.max(np.absolute( + ds_image_cell[var].values))) + 1)) + # --- keep decimal to be no greater than 4 --- # + if decimal > 4: + decimal = 4 + # assert almost equal + np.testing.assert_almost_equal( + ds_image_cell[var].values, df_classic[var].values, + decimal=decimal, + err_msg='Variable {} is different in the classic ' + 'and image drivers'.format(var)) + # if [time, nlayer] + elif len(ds_image_cell[var].coords) == 4: + for l in ds_image['nlayer']: + s_classic = df_classic['{}_{}'.format(var, l.values)] + s_image = ds_image_cell[var].sel(nlayer=l).to_series() + # determine precision for comparison + if np.mean(s_image.values) == 0: + decimal = 2 + else: + decimal = int(round(- np.log10(np.max( + np.absolute(s_image.values))) + 1)) + if decimal > 4: + decimal = 4 + # assert almost eqaul + np.testing.assert_almost_equal( + s_image.values, + s_classic.values, + decimal=decimal, + err_msg='Variable {} is different in the ' + 'classic and image drivers'. + format(var)) + + def tsplit(string, delimiters): '''Behaves like str.split but supports multiple delimiters. ''' From 4365fc5ebfce74be49823207f4c91bf3ad3001bd Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Wed, 17 Aug 2016 20:34:24 -0700 Subject: [PATCH 30/33] change units of image driver forcing VP to kPa from g/g (specific humidity). See GH#418 for discussion --- vic/drivers/image/src/vic_force.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/vic/drivers/image/src/vic_force.c b/vic/drivers/image/src/vic_force.c index 9184a156f..b45a4aeac 100644 --- a/vic/drivers/image/src/vic_force.c +++ b/vic/drivers/image/src/vic_force.c @@ -143,7 +143,7 @@ vic_force(void) } } - // Specific humidity: shum + // vapor pressure: vp for (j = 0; j < NF; j++) { d3start[0] = global_param.forceskip[0] + global_param.forceoffset[0] + j; @@ -361,14 +361,13 @@ vic_force(void) force[i].air_temp[j] -= CONST_TKFRZ; // precipitation in mm/period force[i].prec[j] *= global_param.snow_dt; - // pressure in Pa - // vapor pressure in Pa (we read specific humidity in kg/kg) - force[i].vp[j] = q_to_vp(force[i].vp[j], force[i].pressure[j]); + // vapor pressure in Pa + force[i].vp[j] *= PA_PER_KPA; // vapor pressure deficit in Pa force[i].vpd[j] = svp(force[i].air_temp[j]) - force[i].vp[j]; if (force[i].vpd[j] < 0) { - force[i].vpd[j] = 0; - force[i].vp[j] = svp(force[i].air_temp[j]); + force[i].vpd[j] = 0; + force[i].vp[j] = svp(force[i].air_temp[j]); } // air density in kg/m3 force[i].density[j] = air_density(force[i].air_temp[j], From d562a778761daa60d047b3c42bfc4e98a8ddef37 Mon Sep 17 00:00:00 2001 From: yixinmao Date: Wed, 17 Aug 2016 21:18:00 -0700 Subject: [PATCH 31/33] Science test update (#583) * Add mpi multiprocessing test - test whether the flux and state results using different number of processors are exactly identical for image driver * Add instruction on running VIC image driver using multiple processors to the documentation * Add cross-driver comparison test - half-way finished * Turn on SNOW_BAND in cross-driver testing global param template file * Fixed bugs related to ice heat capacity - In vic_run code, fixed bugs that confused volumetric heat capacity and specific heat capacity related to ice * Combine the volumetric ice heat capacity (per volume of water equivalent) into a single constant * Finished driver comparison test * Fixed a bug in run_tests.py * Made system_tests.cfg consistent with develop branch * Minor formatting * Fixed a bug so that both single- and multi-driver tests are compatible with system, science and example tests * Fixed a bug in run_tests.py to be compatible with science tests * Clean up test code - mostly related to handling cross-driver tests * Removed an unused domain file from test directory * Test code clean up; remove unused domain file under test/example * Update travis build for classic driver and image driver * Fixed a bug when calling run_example * Fixed a bug related to drop_tests * Update science testing: - Updated paths in code and in global parameter template file - Update globap parameter template files for VIC4.2 and VIC5 so that the two versions take in consistent global options (although VIC4.2 is run offline) --- tests/run_tests.py | 20 +- .../global_param.classic.4.2_ecflux.txt | 15 +- .../global_param.classic.4.2_snotel.txt | 25 +- .../global_param.classic.5.0_ecflux.txt | 8 +- .../global_param.classic.5.0_snotel.txt | 10 +- tests/test_utils.py | 357 ++++++++++-------- 6 files changed, 240 insertions(+), 195 deletions(-) diff --git a/tests/run_tests.py b/tests/run_tests.py index d5a240114..5672c0ba3 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -152,6 +152,9 @@ def main(): parser.add_argument('--science_test_data_dir', type=str, help='directory to find science test data', default='./samples/VIC_sample_data') + parser.add_argument('--nproc', type=int, + help='number of processors to use for science tests', + default=1) args = parser.parse_args() @@ -208,7 +211,8 @@ def main(): science_test_data_dir, data_dir, os.path.join(out_dir, 'science'), - 'classic') + 'classic', + args.nproc) # examples if any(i in ['all', 'examples'] for i in args.tests): if len(dict_drivers) == 1: # if only one driver @@ -671,7 +675,7 @@ def run_system(config_file, dict_drivers, test_data_dir, out_dir): def run_science(config_file, vic_exe, science_test_data_dir, - test_data_dir, out_dir, driver): + test_data_dir, out_dir, driver, nproc): '''Run science tests from config file Parameters @@ -688,6 +692,8 @@ def run_science(config_file, vic_exe, science_test_data_dir, Path to output location driver : {'classic', 'image'} Driver to run tests on. + nproc : int + Number of processors to use for science tests Returns ------- @@ -764,6 +770,7 @@ def run_science(config_file, vic_exe, science_test_data_dir, # Run the VIC simulation returncode = vic_exe.run(test_global_file, logdir=dirs['logs'], **run_kwargs) + test_complete = True # Check return code @@ -789,9 +796,6 @@ def run_science(config_file, vic_exe, science_test_data_dir, else: raise ValueError('unknown driver') - # if we got this far, the test passed. - test_passed = True - # plot science test results plot_science_tests(test_dict['driver'], test_type, @@ -799,7 +803,11 @@ def run_science(config_file, vic_exe, science_test_data_dir, dirs['results'], dirs['plots'], test_dict['plots'], - test_dict['compare_data']) + test_dict['compare_data'], + nproc=nproc) + + # if we got this far, the test passed. + test_passed = True # Handle errors except Exception as e: diff --git a/tests/science/global_param.classic.4.2_ecflux.txt b/tests/science/global_param.classic.4.2_ecflux.txt index 0dc459e41..c71981513 100644 --- a/tests/science/global_param.classic.4.2_ecflux.txt +++ b/tests/science/global_param.classic.4.2_ecflux.txt @@ -1,5 +1,5 @@ NLAYER 3 -NODES 3 +NODES 10 TIME_STEP 1 SNOW_STEP 1 STARTYEAR 2000 @@ -13,9 +13,8 @@ ENDDAY 31 FULL_ENERGY TRUE FROZEN_SOIL FALSE -FORCING1 $test_data_dir/datasets/ec_flux_towers/forcing.merge.hourly/full_data_ +FORCING1 $test_data_dir/inputdata/ec_flux_towers/forcing.merge.hourly/full_data_ FORCE_FORMAT ASCII -FORCE_ENDIAN LITTLE N_TYPES 12 FORCE_TYPE SKIP FORCE_TYPE SKIP @@ -37,18 +36,16 @@ FORCEHOUR 00 GRID_DECIMAL 4 WIND_H 10.0 -MEASURE_H 2.0 -ALMA_INPUT FALSE -SOIL $test_data_dir/datasets/ec_flux_towers/params/soil_param.site_test.txt +SOIL $test_data_dir/inputdata/ec_flux_towers/params/soil_param.site_test.txt BASEFLOW ARNO JULY_TAVG_SUPPLIED FALSE ORGANIC_FRACT FALSE -VEGLIB $test_data_dir/datasets/ec_flux_towers/params/veg_lib_IGBP.fv +VEGLIB $test_data_dir/inputdata/ec_flux_towers/params/veg_lib_IGBP.fv VEGLIB_VEGCOVER TRUE -VEGPARAM $test_data_dir/datasets/ec_flux_towers/params/veg_param.sites.IGBP.modis +VEGPARAM $test_data_dir/inputdata/ec_flux_towers/params/veg_param.sites.IGBP.modis ROOT_ZONES 3 VEGPARAM_LAI TRUE @@ -57,7 +54,7 @@ VEGPARAM_ALB TRUE LAI_SRC FROM_VEGPARAM VEGCOVER_SRC FROM_VEGPARAM -ALBEDO_SRC FROM_VEGPARAM +# ALBEDO_SRC FROM_VEGPARAM SNOW_BAND 1 diff --git a/tests/science/global_param.classic.4.2_snotel.txt b/tests/science/global_param.classic.4.2_snotel.txt index b96323ab0..5c6dd22e9 100644 --- a/tests/science/global_param.classic.4.2_snotel.txt +++ b/tests/science/global_param.classic.4.2_snotel.txt @@ -13,20 +13,10 @@ ENDDAY 31 FULL_ENERGY TRUE FROZEN_SOIL FALSE -BLOWING FALSE +QUICK_FLUX FALSE -CORRPREC FALSE -MIN_WIND_SPEED 0.1 -MAX_SNOW_TEMP 0.5 -MIN_RAIN_TEMP -0.5 - -CONTINUEONERROR TRUE - -GRND_FLUX_TYPE GF_FULL - -FORCING1 $test_data_dir/datasets/snotel/forcings_vp/snotel_VIC.4.1.2_forcings_ +FORCING1 $test_data_dir/inputdata/snotel/forcings/snotel_VIC.4.1.2_forcings_ FORCE_FORMAT ASCII -FORCE_ENDIAN LITTLE N_TYPES 7 # Number of variables (columns) FORCE_TYPE SHORTWAVE UNSIGNED 40 FORCE_TYPE LONGWAVE UNSIGNED 40 @@ -41,16 +31,15 @@ FORCEMONTH 11 FORCEDAY 01 FORCEHOUR 00 GRID_DECIMAL 4 -WIND_H 17.5 -MEASURE_H 17.5 -ALMA_INPUT FALSE +# WIND_H 17.5 # WIND_H is not actually used in VIC4.2 (hardcoded) -SOIL $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_soil.txt +SOIL $test_data_dir/inputdata/snotel/parameters/Snotel_VIC.4.1.2_soil.txt BASEFLOW ARNO JULY_TAVG_SUPPLIED FALSE -VEGLIB $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_veglib.txt -VEGPARAM $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_vegparam.txt +ORGANIC_FRACT FALSE +VEGLIB $test_data_dir/inputdata/snotel/parameters/Snotel_VIC.4.1.2_veglib.txt +VEGPARAM $test_data_dir/inputdata/snotel/parameters/Snotel_VIC.4.1.2_vegparam.txt ROOT_ZONES 3 VEGPARAM_LAI TRUE diff --git a/tests/science/global_param.classic.5.0_ecflux.txt b/tests/science/global_param.classic.5.0_ecflux.txt index f961d67c5..7f6b43410 100644 --- a/tests/science/global_param.classic.5.0_ecflux.txt +++ b/tests/science/global_param.classic.5.0_ecflux.txt @@ -16,7 +16,7 @@ FROZEN_SOIL FALSE QUICK_FLUX FALSE -FORCING1 $test_data_dir/datasets/ec_flux_towers/forcing.merge.hourly/full_data_ +FORCING1 $test_data_dir/inputdata/ec_flux_towers/forcing.merge.hourly/full_data_ FORCE_FORMAT ASCII FORCE_TYPE SKIP FORCE_TYPE SKIP @@ -38,15 +38,15 @@ GRID_DECIMAL 4 WIND_H 10.0 -SOIL $test_data_dir/datasets/ec_flux_towers/params/soil_param.site_test.txt +SOIL $test_data_dir/inputdata/ec_flux_towers/params/soil_param.site_test.txt BASEFLOW ARNO JULY_TAVG_SUPPLIED FALSE ORGANIC_FRACT FALSE -VEGLIB $test_data_dir/datasets/ec_flux_towers/params/veg_lib_IGBP.fv +VEGLIB $test_data_dir/inputdata/ec_flux_towers/params/veg_lib_IGBP.fv VEGLIB_FCAN TRUE -VEGPARAM $test_data_dir/datasets/ec_flux_towers/params/veg_param.sites.IGBP.modis +VEGPARAM $test_data_dir/inputdata/ec_flux_towers/params/veg_param.sites.IGBP.modis ROOT_ZONES 3 VEGPARAM_LAI TRUE diff --git a/tests/science/global_param.classic.5.0_snotel.txt b/tests/science/global_param.classic.5.0_snotel.txt index 604d7c26e..8622ef609 100644 --- a/tests/science/global_param.classic.5.0_snotel.txt +++ b/tests/science/global_param.classic.5.0_snotel.txt @@ -16,7 +16,7 @@ FROZEN_SOIL FALSE QUICK_FLUX FALSE -FORCING1 $test_data_dir/datasets/snotel/forcings_vp/snotel_VIC.4.1.2_forcings_ +FORCING1 $test_data_dir/inputdata/snotel/forcings/snotel_VIC.4.1.2_forcings_ FORCE_FORMAT ASCII FORCE_TYPE SWDOWN FORCE_TYPE LWDOWN @@ -31,16 +31,16 @@ FORCEYEAR 2007 FORCEMONTH 11 FORCEDAY 01 GRID_DECIMAL 4 -WIND_H 17.5 +WIND_H 10.0 -SOIL $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_soil.txt +SOIL $test_data_dir/inputdata/snotel/parameters/Snotel_VIC.4.1.2_soil.txt BASEFLOW ARNO JULY_TAVG_SUPPLIED FALSE ORGANIC_FRACT FALSE -VEGLIB $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_veglib.txt -VEGPARAM $test_data_dir/datasets/snotel/parameters/Snotel_VIC.4.1.2_vegparam.txt +VEGLIB $test_data_dir/inputdata/snotel/parameters/Snotel_VIC.4.1.2_veglib.txt +VEGPARAM $test_data_dir/inputdata/snotel/parameters/Snotel_VIC.4.1.2_vegparam.txt ROOT_ZONES 3 VEGPARAM_LAI TRUE diff --git a/tests/test_utils.py b/tests/test_utils.py index 6e71863b2..a55aaad95 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -9,9 +9,12 @@ import xarray as xr import glob import re +import matplotlib +matplotlib.use('Agg') import matplotlib.pyplot as plt import warnings import seaborn as sns +import multiprocessing as mp from tonic.models.vic.vic import (VICRuntimeError, default_vic_valgrind_error_code) @@ -204,6 +207,7 @@ def test_classic_driver_all_complete(fnames): def test_classic_driver_no_output_file_nans(fnames): '''Test that all VIC classic driver output files in fnames have no nans''' for fname in fnames: + print(fname) df = read_vic_ascii(fname) check_for_nans(df) @@ -591,18 +595,16 @@ def read_vic_42_output(lat, lng, science_test_data_dir, items): return vic_42 -def read_vic_5_output(lat, lng, science_test_data_dir, items): +def read_vic_5_output(lat, lng, result_dir, items): ''' Read VIC 5.0.x output. ''' if items['compare_to'] == 'ecflux': vic_5_file = 'en_bal_%s_%s.txt' % (lat, lng) - vic_5_dir = os.path.join(science_test_data_dir, 'science', 'archive', - items['archive'], 'ecflux', 'results') + vic_5_dir = result_dir elif items['compare_to'] == 'snotel': vic_5_file = 'outfile_%s_%s.txt' % (lat, lng) - vic_5_dir = os.path.join(science_test_data_dir, 'science', 'archive', - items['archive'], 'snotel', 'results') + vic_5_dir = result_dir else: raise ValueError("this option (%s) has not yet been implemented" @@ -631,7 +633,7 @@ def read_vic_5_output(lat, lng, science_test_data_dir, items): def plot_science_tests(driver, test_type, science_test_data_dir, result_dir, - plot_dir, plots_to_make, compare_data): + plot_dir, plots_to_make, compare_data, nproc): ''' makes science test figures @@ -652,6 +654,8 @@ def plot_science_tests(driver, test_type, science_test_data_dir, result_dir, compare_data Keys that indicate which datasets and model output to use for comparison. + nproc + Number of processors to use Returns ---------- @@ -662,7 +666,8 @@ def plot_science_tests(driver, test_type, science_test_data_dir, result_dir, compare_data, result_dir, plot_dir, - plots_to_make) + plots_to_make, + nproc) elif test_type == "science_test_fluxnet": plot_fluxnet_comparison(driver, @@ -670,7 +675,8 @@ def plot_science_tests(driver, test_type, science_test_data_dir, result_dir, compare_data, result_dir, plot_dir, - plots_to_make) + plots_to_make, + nproc) else: raise ValueError("this option %s has not been implemented in the \ VIC 5.0 science test suite" % test_type) @@ -679,7 +685,7 @@ def plot_science_tests(driver, test_type, science_test_data_dir, result_dir, def plot_snotel_comparison(driver, science_test_data_dir, compare_data_dict, result_dir, plot_dir, - plots_to_make): + plots_to_make, nproc): ''' makes snotel figures ''' # plot settings @@ -692,16 +698,38 @@ def plot_snotel_comparison(driver, science_test_data_dir, context = "paper" style = "whitegrid" + # --- Set up multiprocessing --- # + pool = mp.Pool(processes=nproc) + for filename in os.listdir(os.path.join(science_test_data_dir, 'science', 'inputdata', 'snotel', 'observations')): + pool.apply_async(plot_snotel_comparison_one_site, + (driver, science_test_data_dir, + compare_data_dict, + result_dir, plot_dir, + plots_to_make, + plot_variables, context, style, filename,)) + + # --- Finish multiprocessing --- # + pool.close() + pool.join() + + +def plot_snotel_comparison_one_site( + driver, science_test_data_dir, + compare_data_dict, + result_dir, plot_dir, + plots_to_make, + plot_variables, context, style, filename): # get lat/lng from filename file_split = re.split('_', filename) lng = file_split[3].split('.txt')[0] lat = file_split[2] + print('Plotting {} {}'.format(lat, lng)) # loop over data to compare data = {} @@ -720,7 +748,7 @@ def plot_snotel_comparison(driver, science_test_data_dir, else: data[key] = read_vic_5_output(lat, lng, - science_test_data_dir, + result_dir, items) # loop over variables to plot @@ -826,8 +854,9 @@ def read_fluxnet_obs(subdir, science_test_data_dir, items): def plot_fluxnet_comparison(driver, science_test_data_dir, compare_data_dict, result_dir, plot_dir, - plots_to_make): - ''' makes Ameriflux figures ''' + plots_to_make, nproc): + ''' makes Ameriflux figures + ''' context = "paper" style = "whitegrid" @@ -845,157 +874,179 @@ def plot_fluxnet_comparison(driver, science_test_data_dir, 'ec_flux_towers', 'obs') + # --- Set up multiprocessing --- # + pool = mp.Pool(processes=nproc) + for subdir in os.listdir(obs_dir): + pool.apply_async(plot_fluxnet_comparison_one_site, + (driver, science_test_data_dir, + compare_data_dict, + result_dir, plot_dir, + plots_to_make, + context, style, var_names, months, obs_dir, subdir,)) - if check_site_files(obs_dir, subdir): - # get CSV file from site directory to get lat/lng for site - lat, lng = get_fluxnet_lat_lon(obs_dir, subdir) - - # loop over data to compare - data = {} - for key, items in compare_data_dict.items(): - - if key == "ecflux": - try: - # load Ameriflux data - data[key] = read_fluxnet_obs(subdir, - science_test_data_dir, - items) - except OSError: - warnings.warn( - "this %s site does not have data" % subdir) - - elif key == "VIC.4.2.d": - try: - # load VIC 4.2 simulations - data[key] = read_vic_42_output(lat, lng, - science_test_data_dir, - items) - - except OSError: - warnings.warn( - "this site has a lat/lng precision issue") - - else: - try: - # load VIC 5 simulations - data[key] = read_vic_5_output(lat, lng, - science_test_data_dir, - items) - except OSError: - warnings.warn( - "this site has a lat/lng precision issue") - - # make figures - - # plot preferences - fs = 15 - dpi = 150 - - if 'annual_mean_diurnal_cycle' in plots_to_make: - - # make annual mean diurnal cycle plots - with plt.rc_context(dict(sns.axes_style(style), - **sns.plotting_context(context))): - f, axarr = plt.subplots(4, 1, figsize=(8, 8), sharex=True) + # --- Finish multiprocessing --- # + pool.close() + pool.join() + + +def plot_fluxnet_comparison_one_site( + driver, science_test_data_dir, + compare_data_dict, + result_dir, plot_dir, + plots_to_make, + context, style, var_names, months, obs_dir, subdir): + + if check_site_files(obs_dir, subdir): + # get CSV file from site directory to get lat/lng for site + lat, lng = get_fluxnet_lat_lon(obs_dir, subdir) + print(lat, lng) + + # loop over data to compare + data = {} + for key, items in compare_data_dict.items(): + + if key == "ecflux": + try: + # load Ameriflux data + data[key] = read_fluxnet_obs(subdir, + science_test_data_dir, + items) + except OSError: + warnings.warn( + "this %s site does not have data" % subdir) + + elif key == "VIC.4.2.d": + try: + # load VIC 4.2 simulations + data[key] = read_vic_42_output(lat, lng, + science_test_data_dir, + items) + + except OSError: + warnings.warn( + "this site has a lat/lng precision issue") - for i, (vic_var, variable_name) in enumerate( - var_names.items()): + else: + try: + # load VIC 5 simulations + data[key] = read_vic_5_output(lat, lng, + result_dir, + items) + except OSError: + warnings.warn( + "this site has a lat/lng precision issue") + + # make figures + + # plot preferences + fs = 15 + dpi = 150 + + if 'annual_mean_diurnal_cycle' in plots_to_make: + + # make annual mean diurnal cycle plots + with plt.rc_context(dict(sns.axes_style(style), + **sns.plotting_context(context))): + f, axarr = plt.subplots(4, 1, figsize=(8, 8), sharex=True) + + for i, (vic_var, variable_name) in enumerate( + var_names.items()): + + # calculate annual mean diurnal cycle for each + # DataFrame + annual_mean = {} + for key, df in data.items(): + annual_mean[key] = pd.DataFrame( + df[vic_var].groupby(df.index.hour).mean()) + + df = pd.DataFrame( + {key: d[vic_var] for key, d in annual_mean.items() + if vic_var in d}) - # calculate annual mean diurnal cycle for each - # DataFrame - annual_mean = {} - for key, df in data.items(): - annual_mean[key] = pd.DataFrame( - df[vic_var].groupby(df.index.hour).mean()) + for key, series in df.iteritems(): + series.plot( + linewidth=compare_data_dict[key]['linewidth'], + ax=axarr[i], + color=compare_data_dict[key]['color'], + linestyle=compare_data_dict[key]['linestyle'], + zorder=compare_data_dict[key]['zorder']) - df = pd.DataFrame( - {key: d[vic_var] for key, d in annual_mean.items() - if vic_var in d}) + axarr[i].legend(loc='upper left') + axarr[i].set_ylabel( + '%s ($W/{m^2}$)' % variable_name, + size=fs) + axarr[i].set_xlabel('Time of Day (Hour)', size=fs) + axarr[i].set_xlim([0, 24]) + axarr[i].xaxis.set_ticks(np.arange(0, 24, 3)) + + # save plot + plotname = '%s_%s.png' % (lat, lng) + os.makedirs(os.path.join(plot_dir, 'annual_mean'), + exist_ok=True) + savepath = os.path.join(plot_dir, 'annual_mean', plotname) + plt.savefig(savepath, bbox_inches='tight', dpi=dpi) + + plt.clf() + plt.close() + + if 'monthly_mean_diurnal_cycle' in plots_to_make: + + # make monthly mean diurnal cycle plots + with plt.rc_context(dict(sns.axes_style(style), + **sns.plotting_context(context))): + f, axarr = plt.subplots(4, 12, figsize=(35, 7), + sharex=True, + sharey=True) + + for i, (vic_var, variable_name) in enumerate( + var_names.items()): + + # calculate monthly mean diurnal cycle + monthly_mean = {} + for (key, df) in data.items(): + monthly_mean[key] = pd.DataFrame( + df[vic_var].groupby([df.index.month, + df.index.hour]).mean()) + + df = pd.DataFrame( + {key: d[vic_var] for key, d in monthly_mean.items() + if vic_var in d}) + + for j, month in enumerate(months): for key, series in df.iteritems(): - series.plot( + series[j + 1].plot( linewidth=compare_data_dict[key]['linewidth'], - ax=axarr[i], + ax=axarr[i, j], color=compare_data_dict[key]['color'], linestyle=compare_data_dict[key]['linestyle'], zorder=compare_data_dict[key]['zorder']) - axarr[i].legend(loc='upper left') - axarr[i].set_ylabel( - '%s ($W/{m^2}$)' % variable_name, + axarr[i, j].set_ylabel( + '%s \n ($W/{m^2}$)' % variable_name, size=fs) - axarr[i].set_xlabel('Time of Day (Hour)', size=fs) - axarr[i].set_xlim([0, 24]) - axarr[i].xaxis.set_ticks(np.arange(0, 24, 3)) - - # save plot - plotname = '%s_%s.png' % (lat, lng) - os.makedirs(os.path.join(plot_dir, 'annual_mean'), - exist_ok=True) - savepath = os.path.join(plot_dir, 'annual_mean', plotname) - plt.savefig(savepath, bbox_inches='tight', dpi=dpi) - - plt.clf() - plt.close() - - if 'monthly_mean_diurnal_cycle' in plots_to_make: - - # make monthly mean diurnal cycle plots - with plt.rc_context(dict(sns.axes_style(style), - **sns.plotting_context(context))): - f, axarr = plt.subplots(4, 12, figsize=(35, 7), - sharex=True, - sharey=True) - - for i, (vic_var, variable_name) in enumerate( - var_names.items()): - - # calculate monthly mean diurnal cycle - monthly_mean = {} - for (key, df) in data.items(): - monthly_mean[key] = pd.DataFrame( - df[vic_var].groupby([df.index.month, - df.index.hour]).mean()) - - df = pd.DataFrame( - {key: d[vic_var] for key, d in monthly_mean.items() - if vic_var in d}) - - for j, month in enumerate(months): - - for key, series in df.iteritems(): - series[j + 1].plot( - linewidth=compare_data_dict[key]['linewidth'], - ax=axarr[i, j], - color=compare_data_dict[key]['color'], - linestyle=compare_data_dict[key]['linestyle'], - zorder=compare_data_dict[key]['zorder']) - - axarr[i, j].set_ylabel( - '%s \n ($W/{m^2}$)' % variable_name, - size=fs) - axarr[i, j].set_xlabel('', size=fs) - axarr[i, j].set_xlim([0, 24]) - axarr[i, j].xaxis.set_ticks(np.arange(0, 24, 3)) - if i == 0: - axarr[i, j].set_title(month, size=fs) - - # add legend - axarr[0, -1].legend(loc='center left', - bbox_to_anchor=(1, 0.5)) - - # add common x label - f.text(0.5, 0.04, 'Time of Day (Hour)', ha='center', - size=fs) - - # save plot - plotname = '%s_%s.png' % (lat, lng) - os.makedirs(os.path.join(plot_dir, 'monthly_mean'), - exist_ok=True) - savepath = os.path.join(plot_dir, - 'monthly_mean', plotname) - plt.savefig(savepath, bbox_inches='tight', dpi=dpi) - - plt.clf() - plt.close() + axarr[i, j].set_xlabel('', size=fs) + axarr[i, j].set_xlim([0, 24]) + axarr[i, j].xaxis.set_ticks(np.arange(0, 24, 3)) + if i == 0: + axarr[i, j].set_title(month, size=fs) + + # add legend + axarr[0, -1].legend(loc='center left', + bbox_to_anchor=(1, 0.5)) + + # add common x label + f.text(0.5, 0.04, 'Time of Day (Hour)', ha='center', + size=fs) + + # save plot + plotname = '%s_%s.png' % (lat, lng) + os.makedirs(os.path.join(plot_dir, 'monthly_mean'), + exist_ok=True) + savepath = os.path.join(plot_dir, + 'monthly_mean', plotname) + plt.savefig(savepath, bbox_inches='tight', dpi=dpi) + + plt.clf() + plt.close() From c06f38fcd08e7179aacd15d65cf535ad591e7e3e Mon Sep 17 00:00:00 2001 From: Bart Nijssen Date: Thu, 18 Aug 2016 08:21:30 -0600 Subject: [PATCH 32/33] logging cleanup (see issue #526) (#581) * logging cleanup (see issue #526) * Removed function names from logging messages * Removed newlines from the end of logging messages (added by log_*() functions) * simplified unnecessary log_warn(); log_err() sequence * One more newline removed * Remove extraneous commas * Removed extraneous error and warning in log_error() --- vic/drivers/cesm/src/cesm_put_data.c | 2 +- vic/drivers/cesm/src/vic_force.c | 2 +- vic/drivers/classic/src/read_atmos_data.c | 6 +- vic/drivers/classic/src/vic_classic.c | 4 +- vic/drivers/classic/src/vic_force.c | 2 +- vic/drivers/image/src/vic_force.c | 2 +- vic/drivers/image/src/vic_image.c | 2 +- .../src/compute_derived_state_vars.c | 7 +- .../shared_all/src/compute_lake_params.c | 2 +- vic/drivers/shared_all/src/forcing_utils.c | 2 +- .../shared_all/src/generate_default_state.c | 7 +- vic/drivers/shared_all/src/get_parameters.c | 2 +- vic/drivers/shared_all/src/timing.c | 2 +- vic/drivers/shared_image/src/vic_init.c | 40 ++++++------ .../shared_image/src/vic_mpi_support.c | 21 +++--- vic/drivers/shared_image/src/vic_nc_info.c | 2 +- vic/drivers/shared_image/src/vic_start.c | 6 +- vic/vic_run/src/CalcBlowingSnow.c | 10 +-- vic/vic_run/src/calc_atmos_energy_bal.c | 56 ++++++++-------- .../src/compute_derived_lake_dimensions.c | 6 +- vic/vic_run/src/func_surf_energy_bal.c | 2 +- vic/vic_run/src/ice_melt.c | 3 +- vic/vic_run/src/lakes.eb.c | 22 +++---- vic/vic_run/src/root_brent.c | 65 +++++++------------ 24 files changed, 124 insertions(+), 151 deletions(-) diff --git a/vic/drivers/cesm/src/cesm_put_data.c b/vic/drivers/cesm/src/cesm_put_data.c index 71b5a94fe..4e04a723a 100644 --- a/vic/drivers/cesm/src/cesm_put_data.c +++ b/vic/drivers/cesm/src/cesm_put_data.c @@ -313,7 +313,7 @@ vic_cesm_put_data() } if (!assert_close_double(AreaFactorSum, 1., 0., 1e-3)) { - log_warn("AreaFactorSum (%f) is not 1 in cesm_put_data.c", + log_warn("AreaFactorSum (%f) is not 1", AreaFactorSum); } } diff --git a/vic/drivers/cesm/src/vic_force.c b/vic/drivers/cesm/src/vic_force.c index e9c680442..252bb5bbd 100644 --- a/vic/drivers/cesm/src/vic_force.c +++ b/vic/drivers/cesm/src/vic_force.c @@ -194,7 +194,7 @@ vic_force(void) } if (options.SNOW_BAND > 1) { - log_err("SNOW_BAND not implemented in vic_force()"); + log_err("SNOW_BAND not implemented"); } else { t_offset = 0; diff --git a/vic/drivers/classic/src/read_atmos_data.c b/vic/drivers/classic/src/read_atmos_data.c index d90acbad4..deab975e4 100644 --- a/vic/drivers/classic/src/read_atmos_data.c +++ b/vic/drivers/classic/src/read_atmos_data.c @@ -108,7 +108,7 @@ read_atmos_data(FILE *infile, // Nbytes is assumed to be the byte offset at which the data records start. fseek(infile, 0, SEEK_SET); if (feof(infile)) { - log_err("No data in the forcing file. Model stopping..."); + log_err("No data in the forcing file."); } for (i = 0; i < 4; i++) { fread(&ustmp, sizeof(unsigned short int), 1, infile); @@ -136,7 +136,7 @@ read_atmos_data(FILE *infile, fseek(infile, skip_recs * Nfields * sizeof(short int), SEEK_CUR); if (feof(infile)) { log_err("No data for the specified time period in the forcing " - "file. Model stopping..."); + "file."); } /** Read BINARY forcing data **/ @@ -216,7 +216,7 @@ read_atmos_data(FILE *infile, for (i = 0; i < skip_recs; i++) { if (fgets(str, MAXSTRING, infile) == NULL) { log_err("No data for the specified time period in the forcing " - "file. Model stopping..."); + "file."); } } diff --git a/vic/drivers/classic/src/vic_classic.c b/vic/drivers/classic/src/vic_classic.c index 6be6111d8..b5ec546d6 100644 --- a/vic/drivers/classic/src/vic_classic.c +++ b/vic/drivers/classic/src/vic_classic.c @@ -277,7 +277,7 @@ main(int argc, "so the simulation has not finished. An " "incomplete output file has been " "generated, check your inputs before " - "rerunning the simulation.\n", + "rerunning the simulation.", soil_con.gridcel, rec); break; } @@ -285,7 +285,7 @@ main(int argc, // Else exit program on cell solution error as in previous versions log_err("ERROR: Grid cell %i failed in record %zu " "so the simulation has ended. Check your " - "inputs before rerunning the simulation.\n", + "inputs before rerunning the simulation.", soil_con.gridcel, rec); } } diff --git a/vic/drivers/classic/src/vic_force.c b/vic/drivers/classic/src/vic_force.c index 5e8a96ed2..36c9f85a7 100644 --- a/vic/drivers/classic/src/vic_force.c +++ b/vic/drivers/classic/src/vic_force.c @@ -263,7 +263,7 @@ vic_force(force_data_struct *force, // Check on fcanopy if (veg_hist[rec][v].fcanopy[i] < MIN_FCANOPY) { log_warn( - "rec %zu, veg %zu substep %zu fcanopy %f < minimum of %f; setting = %f\n", rec, v, i, + "rec %zu, veg %zu substep %zu fcanopy %f < minimum of %f; setting = %f", rec, v, i, veg_hist[rec][v].fcanopy[i], MIN_FCANOPY, MIN_FCANOPY); veg_hist[rec][v].fcanopy[i] = MIN_FCANOPY; diff --git a/vic/drivers/image/src/vic_force.c b/vic/drivers/image/src/vic_force.c index b45a4aeac..c52fd1a84 100644 --- a/vic/drivers/image/src/vic_force.c +++ b/vic/drivers/image/src/vic_force.c @@ -388,7 +388,7 @@ vic_force(void) (options.FCAN_SRC == FROM_VEGHIST))) { // Only issue this warning once if not using veg hist fractions log_warn( - "cell %zu, veg` %d substep %zu fcanopy %f < minimum of %f; setting = %f\n", i, vidx, j, + "cell %zu, veg` %d substep %zu fcanopy %f < minimum of %f; setting = %f", i, vidx, j, veg_hist[i][vidx].fcanopy[j], MIN_FCANOPY, MIN_FCANOPY); veg_hist[i][vidx].fcanopy[j] = MIN_FCANOPY; diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index 5e92219ed..9ad7c04ba 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -158,7 +158,7 @@ main(int argc, // finalize MPI status = MPI_Finalize(); if (status != MPI_SUCCESS) { - log_err("MPI error in main(): %d\n", status); + log_err("MPI error: %d", status); } log_info("Completed running VIC %s", VIC_DRIVER); diff --git a/vic/drivers/shared_all/src/compute_derived_state_vars.c b/vic/drivers/shared_all/src/compute_derived_state_vars.c index b2b557feb..c0a61cabb 100644 --- a/vic/drivers/shared_all/src/compute_derived_state_vars.c +++ b/vic/drivers/shared_all/src/compute_derived_state_vars.c @@ -209,8 +209,8 @@ compute_derived_state_vars(all_vars_struct *all_vars, energy[veg][band].T[1], soil_con->avg_temp); if (ErrorFlag == ERROR) { - log_err("Error in " - "estimate_layer_temperature_quick_flux"); + log_err("Error calculating layer temperature " + "using QUICK_FLUX option"); } } else { @@ -233,8 +233,7 @@ compute_derived_state_vars(all_vars_struct *all_vars, options.Nnode, options.Nlayer); if (ErrorFlag == ERROR) { - log_err("Error in " - "estimate_layer_temperature"); + log_err("Error calculating layer temperature"); } } diff --git a/vic/drivers/shared_all/src/compute_lake_params.c b/vic/drivers/shared_all/src/compute_lake_params.c index 7ac0f0e81..9ed1325bc 100644 --- a/vic/drivers/shared_all/src/compute_lake_params.c +++ b/vic/drivers/shared_all/src/compute_lake_params.c @@ -88,7 +88,7 @@ compute_lake_params(lake_con_struct *lake_con, // compute volume corresponding to mindepth ErrFlag = get_volume(*lake_con, lake_con->mindepth, &(lake_con->minvolume)); if (ErrFlag == ERROR) { - log_err("problem in get_volume(): depth %f volume %f", + log_err("Error calculating depth: depth %f volume %f", lake_con->mindepth, lake_con->minvolume); } } diff --git a/vic/drivers/shared_all/src/forcing_utils.c b/vic/drivers/shared_all/src/forcing_utils.c index bc209d9a8..af9f7feef 100644 --- a/vic/drivers/shared_all/src/forcing_utils.c +++ b/vic/drivers/shared_all/src/forcing_utils.c @@ -37,7 +37,7 @@ average(double *ar, double sum = 0.; if (n <= 0) { - log_err("Error in calc_average: divide by zero or negative"); + log_err("Divide by zero or negative"); } else if (n == 1) { return ar[0]; diff --git a/vic/drivers/shared_all/src/generate_default_state.c b/vic/drivers/shared_all/src/generate_default_state.c index 9f0eaf5ec..7bb50f793 100644 --- a/vic/drivers/shared_all/src/generate_default_state.c +++ b/vic/drivers/shared_all/src/generate_default_state.c @@ -149,8 +149,8 @@ generate_default_state(all_vars_struct *all_vars, soil_con->frost_fract, soil_con->frost_slope, soil_con->FS_ACTIVE); if (ErrorFlag == ERROR) { - log_err("Error in " - "estimate_layer_ice_content_quick_flux"); + log_err("Error calculating layer temperature " + "using QUICK_FLUX option"); } } else { @@ -177,8 +177,7 @@ generate_default_state(all_vars_struct *all_vars, options.Nlayer, soil_con->FS_ACTIVE); if (ErrorFlag == ERROR) { - log_err("Error in " - "estimate_layer_ice_content"); + log_err("Error calculating layer ice content"); } } } diff --git a/vic/drivers/shared_all/src/get_parameters.c b/vic/drivers/shared_all/src/get_parameters.c index 288c4fa7c..45b8aa6f4 100644 --- a/vic/drivers/shared_all/src/get_parameters.c +++ b/vic/drivers/shared_all/src/get_parameters.c @@ -524,7 +524,7 @@ get_parameters(FILE *paramfile) } else { log_warn("Unrecognized option in the parameter file: %s " - "- check your spelling\n", optstr); + "- check your spelling", optstr); } } fgets(cmdstr, MAXSTRING, paramfile); diff --git a/vic/drivers/shared_all/src/timing.c b/vic/drivers/shared_all/src/timing.c index 23691785e..2fb2c2c38 100644 --- a/vic/drivers/shared_all/src/timing.c +++ b/vic/drivers/shared_all/src/timing.c @@ -34,7 +34,7 @@ get_wall_time() { struct timeval time; if (gettimeofday(&time, NULL)) { - log_err("get_wall_time failed") + log_err("Unable to get time of day") } return (double) time.tv_sec + (double) time.tv_usec * 0.000001; } diff --git a/vic/drivers/shared_image/src/vic_init.c b/vic/drivers/shared_image/src/vic_init.c index 0b00483eb..d9e2a978b 100644 --- a/vic/drivers/shared_image/src/vic_init.c +++ b/vic/drivers/shared_image/src/vic_init.c @@ -1302,7 +1302,7 @@ vic_init(void) lake_con[i].lake_idx < (int) veg_con[i][0].vegetat_type_num)) { log_err("cell %zu lake_idx is %d but we must have -1 " - "<= lake_idx < Nveg (%zu).\n", i, lake_con[i].lake_idx, + "<= lake_idx < Nveg (%zu).", i, lake_con[i].lake_idx, veg_con[i][0].vegetat_type_num); } if (lake_con[i].lake_idx != -1) { @@ -1320,19 +1320,19 @@ vic_init(void) if (lake_con[i].numnod != 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires numnod to be 0, but numnod is " - "%zu\n", i, lake_con[i].lake_idx, + "%zu.", i, lake_con[i].lake_idx, lake_con[i].numnod); } } else if (!(lake_con[i].numnod > 0 && lake_con[i].numnod < MAX_LAKE_NODES)) { log_err("cell %zu numnod is %zu but we must have 1 " - "<= numnod < %d.\n", i, lake_con[i].numnod, + "<= numnod < %d.", i, lake_con[i].numnod, MAX_LAKE_NODES); } else if (!(lake_con[i].numnod <= options.NLAKENODES)) { log_err("cell %zu numnod is %zu but this exceeds " - "the file lake_node dimension length of %zu.\n", + "the file lake_node dimension length of %zu.", i, lake_con[i].numnod, options.NLAKENODES); } if (lake_con[i].numnod > max_numnod) { @@ -1349,13 +1349,13 @@ vic_init(void) if (lake_con[i].mindepth != 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires mindepth to be 0, but mindepth " - "is %f\n", i, lake_con[i].lake_idx, + "is %f.", i, lake_con[i].lake_idx, lake_con[i].mindepth); } } else if (lake_con[i].lake_idx != -1 && !(lake_con[i].mindepth >= 0)) { - log_err("cell %zu mindepth is %f but must be >= 0.\n", + log_err("cell %zu mindepth is %f but must be >= 0.", i, lake_con[i].mindepth); } } @@ -1369,13 +1369,13 @@ vic_init(void) if (lake_con[i].wfrac != 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires wfrac to be 0, but wfrac is " - "%f\n", i, lake_con[i].lake_idx, lake_con[i].wfrac); + "%f.", i, lake_con[i].lake_idx, lake_con[i].wfrac); } } else if (lake_con[i].lake_idx != -1 && !(lake_con[i].wfrac >= 0 && lake_con[i].wfrac <= 1)) { log_err("cell %zu wfrac is %f but we must have " - "0 <= wfrac <= 1.\n", i, lake_con[i].wfrac); + "0 <= wfrac <= 1.", i, lake_con[i].wfrac); } } @@ -1388,13 +1388,13 @@ vic_init(void) if (lake_con[i].depth_in != 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires depth_in to be 0, but depth_in is " - "%f\n", i, lake_con[i].lake_idx, + "%f.", i, lake_con[i].lake_idx, lake_con[i].depth_in); } } else if (lake_con[i].lake_idx != -1 && !(lake_con[i].depth_in >= 0)) { - log_err("cell %zu depth_in is %f but must be >= 0.\n", + log_err("cell %zu depth_in is %f but must be >= 0.", i, lake_con[i].depth_in); } } @@ -1408,7 +1408,7 @@ vic_init(void) if (lake_con[i].rpercent != 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires rpercent to be 0, but rpercent is " - "%f\n", i, lake_con[i].lake_idx, + "%f.", i, lake_con[i].lake_idx, lake_con[i].rpercent); } } @@ -1416,7 +1416,7 @@ vic_init(void) !(lake_con[i].rpercent >= 0 && lake_con[i].rpercent <= 1)) { log_err("cell %zu rpercent is %f but we must have " - "0 <= rpercent <= 1.\n", i, lake_con[i].rpercent); + "0 <= rpercent <= 1.", i, lake_con[i].rpercent); } } @@ -1469,36 +1469,36 @@ vic_init(void) if (lake_con[i].z[0] > 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires max depth to be 0, but max depth " - "is %f\n", i, lake_con[i].lake_idx, + "is %f.", i, lake_con[i].lake_idx, lake_con[i].z[0]); } if (lake_con[i].Cl[0] > 0) { log_err("cell %zu lake_idx is %d (lake not present) " "which requires max area fraction to be 0, but " - "max area fraction is %f\n", i, + "max area fraction is %f.", i, lake_con[i].lake_idx, lake_con[i].Cl[0]); } } else { if (!(lake_con[i].z[0] > 0)) { log_err("cell %zu lake basin max depth is %f but must " - "be > 0.\n", i, lake_con[i].z[0]); + "be > 0.", i, lake_con[i].z[0]); } else if (!(lake_con[i].mindepth <= lake_con[i].z[0])) { log_err("cell %zu lake basin mindepth is %f but " - "must be <= max depth of %f\n", + "must be <= max depth of %f.", i, lake_con[i].mindepth, lake_con[i].z[0]); } if (!(lake_con[i].Cl[0] > 0 && lake_con[i].Cl[0] <= 1)) { log_err("cell %zu lake basin max area fraction is %f but " - "we must have 0 < max area fraction < 1\n", i, + "we must have 0 < max area fraction < 1.", i, lake_con[i].Cl[0]); } if (fabs(1 - lake_con[i].Cl[0] / veg_con[i][lake_con[i].lake_idx].Cv) > 0.01) { log_err("cell %zu lake basin max area fraction is %f but " "must == area fraction of veg tile containing " - "lake (%f)\n", i, lake_con[i].Cl[0], + "lake (%f).", i, lake_con[i].Cl[0], veg_con[i][lake_con[i].lake_idx].Cv); } else { @@ -1512,7 +1512,7 @@ vic_init(void) if (!(lake_con[i].z[j] > 0 && lake_con[i].z[j] < lake_con[i].z[j - 1])) { log_err("cell %zu lake basin node %zu depth is %f " - "but must be > 0 and < node %zu depth %f\n", + "but must be > 0 and < node %zu depth %f.", i, j, lake_con[i].z[j], j - 1, lake_con[i].z[j - 1]); } @@ -1520,7 +1520,7 @@ vic_init(void) lake_con[i].Cl[j] < lake_con[i].Cl[j - 1])) { log_err("cell %zu lake basin node %zu area fraction " "is %f but must be > 0 and < node %zu area " - "fraction %f\n", i, j, lake_con[i].Cl[j], j - 1, + "fraction %f.", i, j, lake_con[i].Cl[j], j - 1, lake_con[i].Cl[j - 1]); } } diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index 127d5499b..67436c7ec 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -256,8 +256,7 @@ create_MPI_global_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount in create_MPI_global_struct_type(): " - "%zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -358,8 +357,7 @@ create_MPI_filenames_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount in create_MPI_filenames_struct_type(): " - "%zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -453,8 +451,7 @@ create_MPI_location_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount in create_MPI_location_struct_type(): " - "%zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -723,8 +720,7 @@ create_MPI_option_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount in create_MPI_option_struct_type(): " - "%zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -1391,8 +1387,7 @@ create_MPI_param_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount in create_MPI_param_struct_type(): " - "%zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -1466,7 +1461,7 @@ create_MPI_dmy_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount: %zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -1547,7 +1542,7 @@ create_MPI_alarm_struct_type(MPI_Datatype *mpi_type) // make sure that the we have the right number of elements if (i != (size_t) nitems) { - log_err("Miscount: %zd not equal to %d\n", i, nitems); + log_err("Miscount: %zd not equal to %d.", i, nitems); } status = MPI_Type_create_struct(nitems, blocklengths, offsets, mpi_types, @@ -1744,7 +1739,7 @@ gather_put_nc_field_double(int nc_id, filter_active_cells, dvar_remapped, dvar); status = nc_put_vara_double(nc_id, var_id, start, count, dvar); - check_nc_status(status, "Error writing values"); + check_nc_status(status, "Error writing values."); // cleanup free(dvar); free(dvar_gathered); diff --git a/vic/drivers/shared_image/src/vic_nc_info.c b/vic/drivers/shared_image/src/vic_nc_info.c index bc0c9eaa4..6867f5b84 100644 --- a/vic/drivers/shared_image/src/vic_nc_info.c +++ b/vic/drivers/shared_image/src/vic_nc_info.c @@ -243,7 +243,7 @@ get_nc_dtype(unsigned short int dtype) type = NC_DOUBLE; break; default: - log_err("Unrecognized netCDF variable datatype %hu", dtype); + log_err("Unrecognized netCDF variable datatype: %hu", dtype); } return type; } diff --git a/vic/drivers/shared_image/src/vic_start.c b/vic/drivers/shared_image/src/vic_start.c index 7090b515b..ca94d0bc4 100644 --- a/vic/drivers/shared_image/src/vic_start.c +++ b/vic/drivers/shared_image/src/vic_start.c @@ -150,7 +150,7 @@ vic_start(void) local_domain.locations = malloc(local_domain.ncells_active * sizeof(*local_domain.locations)); if (local_domain.locations == NULL) { - log_err("malloc error in vic_start()\n"); + log_err("malloc error"); } for (i = 0; i < local_domain.ncells_active; i++) { initialize_location(&(local_domain.locations[i])); @@ -161,7 +161,7 @@ vic_start(void) mapped_locations = malloc(global_domain.ncells_active * sizeof(*mapped_locations)); if (mapped_locations == NULL) { - log_err("malloc error in vic_start()\n"); + log_err("malloc error"); } for (i = 0; i < global_domain.ncells_active; i++) { initialize_location(&(mapped_locations[i])); @@ -170,7 +170,7 @@ vic_start(void) active_locations = (location_struct *) malloc( global_domain.ncells_active * sizeof(location_struct)); if (active_locations == NULL) { - log_err("malloc error in vic_start()\n"); + log_err("malloc error"); } for (i = 0; i < global_domain.ncells_active; i++) { initialize_location(&(active_locations[i])); diff --git a/vic/vic_run/src/CalcBlowingSnow.c b/vic/vic_run/src/CalcBlowingSnow.c index 3baf925e6..84357919d 100644 --- a/vic/vic_run/src/CalcBlowingSnow.c +++ b/vic/vic_run/src/CalcBlowingSnow.c @@ -304,7 +304,7 @@ qromb(double (*funcd)(), } h[j + 1] = 0.25 * h[j]; } - log_err("Too many steps in routine qromb"); + log_err("Too many steps"); } /****************************************************************************** @@ -346,7 +346,7 @@ polint(double xa[], hp = xa[i + m] - x; w = c[i + 1] - d[i]; if ((den = ho - hp) == 0.0) { - log_err("Error in routine polint"); + log_err("interpolation error"); } den = w / den; d[i] = hp * den; @@ -427,7 +427,7 @@ rtnewt(double x1, get_shear(x2, &fh, &df, Ur, Zr); if ((fl > 0.0 && fh > 0.0) || (fl < 0.0 && fh < 0.0)) { - log_err("Root must be bracketed in rtnewt."); + log_err("Root must be bracketed"); } if (fl == 0.0) { @@ -479,7 +479,7 @@ rtnewt(double x1, xh = rts; } } - log_err("Maximum number of iterations exceeded in rtnewt."); + log_err("Maximum number of iterations exceeded"); } /****************************************************************************** @@ -678,7 +678,7 @@ shear_stress(double U10, get_shear(umax, &fh, &df, U10, 10.); if (fl < 0.0 && fh < 0.0) { - log_err("Solution in rtnewt surpasses upper boundary." + log_err("Solution surpasses upper boundary." "fl(%f)=%f, fh(%f)=%f", umin, fl, umax, fh); } diff --git a/vic/vic_run/src/calc_atmos_energy_bal.c b/vic/vic_run/src/calc_atmos_energy_bal.c index a7578ee13..c5fb94d4b 100644 --- a/vic/vic_run/src/calc_atmos_energy_bal.c +++ b/vic/vic_run/src/calc_atmos_energy_bal.c @@ -199,23 +199,20 @@ error_print_atmos_energy_bal(double Tcanopy, ErrorString = (char *)va_arg(ap, char *); // print variable values - fprintf(LOG_DEST, "%s", ErrorString); - fprintf(LOG_DEST, "ERROR: calc_atmos_energy_bal failed to converge to a " - "solution in root_brent. Variable values will be dumped " - "to the screen, check for invalid values.\n"); - fprintf(LOG_DEST, "Tcanopy = %f\n", Tcanopy); - fprintf(LOG_DEST, "LatentHeat = %f\n", LatentHeat); - fprintf(LOG_DEST, "NetRadiation = %f\n", NetRadiation); - fprintf(LOG_DEST, "Ra = %f\n", Ra); - fprintf(LOG_DEST, "Tair = %f\n", Tair); - fprintf(LOG_DEST, "atmos_density = %f\n", atmos_density); - fprintf(LOG_DEST, "InSensible = %f\n", InSensible); - - fprintf(LOG_DEST, "*SensibleHeat = %f\n", *SensibleHeat); - - fprintf(LOG_DEST, "Finished writing calc_atmos_energy_bal variables.\n" - "Try increasing CANOPY_DT to get model to complete cell.\n" - "Then check output for instabilities.\n"); + log_warn("Failure to converge to a solution in root_brent.\n" + "Check for invalid values.\n" + "Tcanopy = %f\n" + "LatentHeat = %f\n" + "NetRadiation = %f\n" + "Ra = %f\n" + "Tair = %f\n" + "atmos_density = %f\n" + "InSensible = %f\n" + "*SensibleHeat = %f\n" + "Try increasing CANOPY_DT to get model to complete cell.\n" + "Then check output for instabilities.", + Tcanopy, LatentHeat, NetRadiation, Ra, Tair, atmos_density, + InSensible, *SensibleHeat); return(ERROR); } @@ -284,19 +281,18 @@ error_print_atmos_moist_bal(double VPcanopy, ErrorString = (char *) va_arg(ap, char *); // print variable values - fprintf(LOG_DEST, "%s", ErrorString); - fprintf(LOG_DEST, "VPcanopy = %f\n", VPcanopy); - fprintf(LOG_DEST, "InLatent = %f\n", InLatent); - fprintf(LOG_DEST, "Lv = %f\n", Lv); - fprintf(LOG_DEST, "Ra = %f\n", Ra); - fprintf(LOG_DEST, "atmos_density = %f\n", atmos_density); - fprintf(LOG_DEST, "gamma = %f\n", gamma); - fprintf(LOG_DEST, "vp = %f\n", vp); - fprintf(LOG_DEST, "AtmosLatent = %f\n", *AtmosLatent); - - log_err("Finished writing calc_atmos_moist_bal variables.\nTry increasing " - "CANOPY_VP to get model to complete cell.\nThen check output for " - "instabilities."); + log_err("VPcanopy = %f\n" + "InLatent = %f\n" + "Lv = %f\n" + "Ra = %f\n" + "atmos_density = %f\n" + "gamma = %f\n" + "vp = %f\n" + "AtmosLatent = %f\n" + "Try increasing CANOPY_VP to get model to complete cell.\n" + "Then check output for instabilities.", + VPcanopy, InLatent, Lv, Ra, atmos_density, gamma, vp, + *AtmosLatent); return(0.0); } diff --git a/vic/vic_run/src/compute_derived_lake_dimensions.c b/vic/vic_run/src/compute_derived_lake_dimensions.c index a97cc7280..23a8c5918 100644 --- a/vic/vic_run/src/compute_derived_lake_dimensions.c +++ b/vic/vic_run/src/compute_derived_lake_dimensions.c @@ -85,7 +85,7 @@ compute_derived_lake_dimensions(lake_var_struct *lake, } status = get_sarea(lake_con, depth, &(lake->surface[k])); if (status < 0) { - log_err("Error in get_sarea: record = %d, depth = %f, " + log_err("record = %d, depth = %f, " "sarea = %e", 0, depth, lake->surface[k]); } } @@ -93,11 +93,11 @@ compute_derived_lake_dimensions(lake_var_struct *lake, lake->sarea = lake->surface[0]; status = get_volume(lake_con, lake->ldepth, &tmp_volume); if (status < 0) { - log_err("Error in get_volume: record = %d, depth = %f, " + log_err("record = %d, depth = %f, " "volume = %e", 0, depth, tmp_volume); } else if (status > 0) { - log_err("Warning in get_volume: lake depth exceeds maximum; " + log_err("lake depth exceeds maximum; " "setting to maximum; record = %d", 0); } lake->volume = tmp_volume + lake->ice_water_eq; diff --git a/vic/vic_run/src/func_surf_energy_bal.c b/vic/vic_run/src/func_surf_energy_bal.c index fa828f490..1fe7ef4ca 100644 --- a/vic/vic_run/src/func_surf_energy_bal.c +++ b/vic/vic_run/src/func_surf_energy_bal.c @@ -468,7 +468,7 @@ func_surf_energy_bal(double Ts, } if ((int) Error == ERROR) { - log_err("func_surf_energy_bal calling solve_T_profile"); + log_err("Error solving the temperature profile"); } /* Compute temperatures for calculations of ground heat flux, delta_H, and fusion */ if (!options.EXP_TRANS) { diff --git a/vic/vic_run/src/ice_melt.c b/vic/vic_run/src/ice_melt.c index 9e906f338..e6b6efe46 100644 --- a/vic/vic_run/src/ice_melt.c +++ b/vic/vic_run/src/ice_melt.c @@ -209,8 +209,7 @@ ice_melt(double z2, snow->surf_temp, 0, 1, 100., .067, .0123, &snow->transport); if ((int)snow->blowing_flux == ERROR) { - log_err("ice_melt.c has an error from the call to " - "CalcBlowingSnow. Exiting module."); + log_err("Error calculating blowing snow flux"); } snow->blowing_flux *= delta_t / CONST_RHOFW; diff --git a/vic/vic_run/src/lakes.eb.c b/vic/vic_run/src/lakes.eb.c index c858779cd..2242c7ccf 100644 --- a/vic/vic_run/src/lakes.eb.c +++ b/vic/vic_run/src/lakes.eb.c @@ -1896,13 +1896,13 @@ water_balance(lake_var_struct *lake, volume_save = lake->volume; ErrorFlag = get_depth(lake_con, lake->volume - lake->ice_water_eq, &ldepth); if (ErrorFlag == ERROR) { - log_err("Something went wrong in get_depth; " - "volume = %f, depth = %e", lake->volume, ldepth); + log_err("Error calculating depth: volume = %f, depth = %e", + lake->volume, ldepth); } ErrorFlag = get_sarea(lake_con, ldepth, &surfacearea); if (ErrorFlag == ERROR) { - log_err("Something went wrong in get_sarea; depth = %f, " - "sarea = %e", ldepth, surfacearea); + log_err("Error calculating area: depth = %f, sarea = %e", + ldepth, surfacearea); } // Estimate the new lake fraction (before recharge) @@ -2045,12 +2045,12 @@ water_balance(lake_var_struct *lake, // baseflow will only come from under the liquid portion of the lake ErrorFlag = get_depth(lake_con, lake->volume - lake->ice_water_eq, &ldepth); if (ErrorFlag == ERROR) { - log_err("Something went wrong in get_depth; volume = %f, " - "depth = %e", lake->volume, ldepth); + log_err("Error calculating depth: volume = %f, depth = %e", + lake->volume, ldepth); } ErrorFlag = get_sarea(lake_con, ldepth, &surfacearea); if (ErrorFlag == ERROR) { - log_err("Error in get_sarea; depth = %f, sarea = %e", + log_err("Error calculating area: depth = %f, sarea = %e", ldepth, surfacearea); } lake->baseflow_out = baseflow_out_mm * surfacearea / MM_PER_M; @@ -2065,8 +2065,8 @@ water_balance(lake_var_struct *lake, // Find new lake depth for runoff calculations ErrorFlag = get_depth(lake_con, lake->volume - lake->ice_water_eq, &ldepth); if (ErrorFlag == ERROR) { - log_err("Something went wrong in get_depth; volume = %f, " - "depth = %e", lake->volume, ldepth); + log_err("Error calculating depth: volume = %f, depth = %e", + lake->volume, ldepth); } // Compute runoff volume in m^3 and extract runoff volume from lake @@ -2126,8 +2126,8 @@ water_balance(lake_var_struct *lake, ErrorFlag = get_depth(lake_con, lake->volume - lake->ice_water_eq, &(lake->ldepth)); if (ErrorFlag == ERROR) { - log_err("Something went wrong in get_depth; volume = %f, " - "depth = %e", lake->volume, lake->ldepth); + log_err("Error calculating depth: volume = %f, depth = %e", + lake->volume, lake->ldepth); } /********************************************************************** diff --git a/vic/vic_run/src/root_brent.c b/vic/vic_run/src/root_brent.c index 1a9a3522e..d44284f2a 100644 --- a/vic/vic_run/src/root_brent.c +++ b/vic/vic_run/src/root_brent.c @@ -73,7 +73,6 @@ root_brent(double LowerBound, { extern parameters_struct param; - const char *Routine = "RootBrent"; va_list ap; /* Used in traversing variable argument list */ double a; double b; @@ -107,10 +106,9 @@ root_brent(double LowerBound, // If Function returns values of ERROR for both bounds, give up if (fa == ERROR && fb == ERROR) { - sprintf(ErrorString, "ERROR: %s: lower and upper bounds %f and %f " - "failed to bracket the root because the given function was " - "not defined at either point.\n", Routine, a, b); - log_warn("Root Brent is returning an error: %s", ErrorString); + log_warn("lower and upper bounds %f and %f " + "failed to bracket the root because the given function was " + "not defined at either point.", a, b); va_end(ap); return(ERROR); } @@ -146,11 +144,10 @@ root_brent(double LowerBound, if (fc == ERROR) { /* if we get here, we could not find a bound for which the function returns a valid value */ - sprintf(ErrorString, "ERROR: %s: the given function produced " + log_warn("the given function produced " "undefined values while attempting to " "bracket the root between %f and %f. Driver info: %s.", - Routine, LowerBound, UpperBound, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", ErrorString); + LowerBound, UpperBound, vic_run_ref_str); va_end(ap); return(ERROR); } @@ -189,13 +186,11 @@ root_brent(double LowerBound, fb = Function(b, ap); if (fb == ERROR) { /* Undefined function values in both directions - give up */ - sprintf(ErrorString, "ERROR: %s: the given function " - "produced undefined values while " - "attempting to bracket the root " - "between %f and %f. Driver info: %s.", - Routine, LowerBound, UpperBound, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", - ErrorString); + log_warn("the given function " + "produced undefined values while " + "attempting to bracket the root " + "between %f and %f. Driver info: %s.", + LowerBound, UpperBound, vic_run_ref_str); va_end(ap); return(ERROR); } @@ -207,13 +202,10 @@ root_brent(double LowerBound, fa = Function(a, ap); if (fa == ERROR) { /* Undefined function values in both directions - give up */ - sprintf(ErrorString, - "ERROR: %s: the given function produced undefined " - "values while attempting to bracket the root " - "between %f and %f. Driver info: %s.", - Routine, LowerBound, UpperBound, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", - ErrorString); + log_warn("the given function produced undefined " + "values while attempting to bracket the root " + "between %f and %f. Driver info: %s.", + LowerBound, UpperBound, vic_run_ref_str); va_end(ap); return(ERROR); } @@ -235,12 +227,10 @@ root_brent(double LowerBound, if (fc == ERROR) { /* if we get here, we could not find a bound for which the function returns a valid value */ - sprintf(ErrorString, - "ERROR: %s: the given function produced undefined " - "values while attempting to bracket the root between " - "%f and %f. Driver info: %s.", - Routine, LowerBound, UpperBound, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", ErrorString); + log_warn("the given function produced undefined " + "values while attempting to bracket the root between " + "%f and %f. Driver info: %s.", + LowerBound, UpperBound, vic_run_ref_str); va_end(ap); return(ERROR); } @@ -260,11 +250,9 @@ root_brent(double LowerBound, } if ((fa * fb) >= 0) { /* if we get here, the lower and upper bounds did not bracket the root */ - sprintf(ErrorString, - "WARNING: %s: lower and upper bounds %f and %f failed to " - "bracket the root. Driver info: %s.", - Routine, a, b, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", ErrorString); + log_warn("lower and upper bounds %f and %f failed to " + "bracket the root. Driver info: %s.", + a, b, vic_run_ref_str); va_end(ap); return(ERROR); } @@ -347,19 +335,16 @@ root_brent(double LowerBound, // Catch ERROR values returned from Function if (fb == ERROR) { - sprintf(ErrorString, "ERROR returned to root_brent on " - "iteration %d: temperature = %.4f. Driver info: %s.", - i + 1, b, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", ErrorString); + log_warn("iteration %d: temperature = %.4f. Driver info: %s.", + i + 1, b, vic_run_ref_str); va_end(ap); return(ERROR); } } } /* If we get here, there were too many iterations */ - sprintf(ErrorString, "WARNING: %s: too many iterations. Driver info: %s.", - Routine, vic_run_ref_str); - log_warn("Root Brent is returning an error: %s", ErrorString); + log_warn("too many iterations. Driver info: %s.", + vic_run_ref_str); va_end(ap); return(ERROR); } From f3ac38d97268020f6335b44e0dbc8eb476fb1331 Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 18 Aug 2016 07:22:21 -0700 Subject: [PATCH 33/33] updates for rc2 tomorrow (#585) * updates for rc2 tomorrow * run uncrustify --- docs/Development/ReleaseNotes.md | 7 +++---- vic/drivers/python/setup.py | 2 +- vic/drivers/shared_all/include/vic_version.h | 4 ++-- vic/vic_run/src/ice_melt.c | 6 +++--- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/Development/ReleaseNotes.md b/docs/Development/ReleaseNotes.md index f2bbf7bdd..5839ba9ff 100644 --- a/docs/Development/ReleaseNotes.md +++ b/docs/Development/ReleaseNotes.md @@ -15,9 +15,9 @@ For VIC 5 and later, type `vic _{classic,image}.exe -v` ------------------------------ -## VIC 5.0.0 (Release Candidate 1) +## VIC 5.0.0 (Release Candidate 2) -**Release date: June 28, 2016** +**Release date: August 18, 2016** This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly identical physics as VIC 4.2 while providing a clean, refactored code base supporting multiple drivers. There are a number of new features, bug fixes, and backward incompatible changes. See the VIC Github page for more details on the changes included in this release. @@ -60,7 +60,7 @@ This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly ide 9. Tests Datasets ([GH#79](https://github.com/UW-Hydro/VIC/issues/79)) - **TODO:** See https://github.com/UW-Hydro/VIC/issues/79 for more information. + See https://github.com/UW-Hydro/VIC/issues/79 for more information. A temporary location of the test data is here: ftp://ftp.hydro.washington.edu/pub/gergel/VIC5_test_data/ 10. Testing and Continuous Integration ([GH#190](https://github.com/UW-Hydro/VIC/pull/190)) @@ -76,7 +76,6 @@ This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly ide The format of ASCII forcing and output files has changed in VIC 5. These changes were motivated by the desire to improve simulation metadata tracking and reproducibility of VIC simulations. - - Forcing files now require date stamps for each timestep and a header specifies the names of the forcing variables. - Output files now include a header with simulation metadata and variable names. The `PRT_HEADER` option has been deprecated. 2. Classic Driver Global Parameter Options diff --git a/vic/drivers/python/setup.py b/vic/drivers/python/setup.py index c3cbf1ceb..73425b38a 100644 --- a/vic/drivers/python/setup.py +++ b/vic/drivers/python/setup.py @@ -28,7 +28,7 @@ MICRO = 0 ISRELEASED = True VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO) -QUALIFIER = 'rc1' +QUALIFIER = 'rc2' FULLVERSION = VERSION write_version = False diff --git a/vic/drivers/shared_all/include/vic_version.h b/vic/drivers/shared_all/include/vic_version.h index 3f1b191ae..70dae5726 100644 --- a/vic/drivers/shared_all/include/vic_version.h +++ b/vic/drivers/shared_all/include/vic_version.h @@ -31,11 +31,11 @@ #define STR(x) STR_HELPER(x) #ifndef VERSION -#define VERSION "5.0.0 Release Candidate 1: June 28, 2016" +#define VERSION "5.0.0 Release Candidate 2: August 18, 2016" #endif #ifndef SHORT_VERSION -#define SHORT_VERSION "5.0.0.rc1" +#define SHORT_VERSION "5.0.0.rc2" #endif #ifndef GIT_VERSION diff --git a/vic/vic_run/src/ice_melt.c b/vic/vic_run/src/ice_melt.c index e6b6efe46..0892630c6 100644 --- a/vic/vic_run/src/ice_melt.c +++ b/vic/vic_run/src/ice_melt.c @@ -509,9 +509,9 @@ ice_melt(double z2, PackCC = (PackSwq + PackIce) * CONST_VCPICE_WQ * snow->pack_temp + - PackRefreezeEnergy; + PackRefreezeEnergy; snow->pack_temp = PackCC / (CONST_VCPICE_WQ * - (PackSwq + PackIce)); + (PackSwq + PackIce)); if (snow->pack_temp > 0.) { snow->pack_temp = 0.; } @@ -568,7 +568,7 @@ ice_melt(double z2, SurfaceSwq += param.SNOW_MAX_SURFACE_SWE - SurfaceSwq; } snow->pack_temp = PackCC / (CONST_VCPICE_WQ * - (PackSwq + PackIce)); + (PackSwq + PackIce)); snow->surf_temp = SurfaceCC / (CONST_VCPICE_WQ * SurfaceSwq); } else {