diff --git a/ci/image.travis b/ci/image.travis index cc035be03..72e41fb23 100644 --- a/ci/image.travis +++ b/ci/image.travis @@ -81,6 +81,10 @@ function vic_script { $DRIVER_EXE -v $DRIVER_EXE -o + # Set the number of OpenMP threads to use + # https://docs.travis-ci.com/user/languages/c/#OpenMP-projects + export OMP_NUM_THREADS=4 + # Run test package ./tests/run_tests.py unit examples system \ --image=${DRIVER_EXE} \ diff --git a/docs/Development/ReleaseNotes.md b/docs/Development/ReleaseNotes.md index ba60d5d09..450c58742 100644 --- a/docs/Development/ReleaseNotes.md +++ b/docs/Development/ReleaseNotes.md @@ -25,16 +25,91 @@ To check which release of VIC you are running: Drainage from upper layer to adjacent lower layer is calculated according to Brook & Corey curve (where drainage rate is a function of upper-layer soil moisture). In previous versions, a simple numerical solution is applied which uses the timestep-beginning upper-layer soil moisture to calculate drainage rate, and assume this constant rate over the entire timestep. This can cause unreasonably large drainage if the curve has a steep shape and when soil moisture is high. Now, the current version uses exact integral (instead of numerical solution) for layer drainage calculation. -2. Fixes for the CESM driver ([GH#642](https://github.com/UW-Hydro/VIC/pull/642)) +2. Fixes for the CESM driver - 1. Using correct fill value datatypes in MPI Gather steps - 2. Updated state file name time step to be period-ending rather than period-beginning - 3. Set the state file name to the RASM case ID - 4. Removed decimal point for missing values for unsigned integers - 5. Create dummy forcings when initializing the model (so that there is forcing data for the first time step) - 6. Changed pressure units from kPa to Pa - 7. Fixed bug that prevented using the correct local domain grid cells in `cesm_put_data.c` - 8. Changed reference temperature units from Celsius to Kelvin in `cesm_put_data.c` + [GH#642](https://github.com/UW-Hydro/VIC/pull/642) + + 1. Using correct fill value datatypes in MPI Gather steps + 2. Updated state file name time step to be period-ending rather than period-beginning + 3. Set the state file name to the RASM case ID + 4. Removed decimal point for missing values for unsigned integers + 5. Create dummy forcings when initializing the model (so that there is forcing data for the first time step) + 6. Changed pressure units from kPa to Pa + 7. Fixed bug that prevented using the correct local domain grid cells in `cesm_put_data.c` + 8. Changed reference temperature units from Celsius to Kelvin in `cesm_put_data.c` + + [GH#695](https://github.com/UW-Hydro/VIC/pull/695) + + 1. Fix sign for latent heat fluxes passed from VIC to the coupler + 2. Fix sign for longwave radiation passed from VIC to the coupler + + [GH#696](https://github.com/UW-Hydro/VIC/pull/696) + + Changes names of CESM driver functions `trim` and `advance_time` to `trimstr` and `advance_vic_time`, respectively, to avoid conflicts with WRF functions with the same names when compiling RFR case. + + [GH#702] (https://github.com/UW-Hydro/VIC/pull/702) + + Fixes Julian day for the first timestep in the dmy struct for the CESM driver. + + [GH#710] (https://github.com/UW-Hydro/VIC/pull/710) + + Refactor the cesm_put_data.c routine in the CESM driver to use values from out_data directly, rather than computing them separately in cesm_put_data.c. + + [GH#716] (https://github.com/UW-Hydro/VIC/pull/716) + + Fixes initialization of coupler fields and calculates temperature and upwelling longwave to pass to WRF during initialization. + + [GH#718] (https://github.com/UW-Hydro/VIC/pull/718) + + Updates the cesm_put_data.c routine in the CESM driver to pass gridcell-averaged albedo to the coupler. + + [GH#726] (https://github.com/UW-Hydro/VIC/pull/726) + + Updates the cesm_put_data.c routine in the CESM driver to include the correct units for evap passed to the coupler. + + [GH#732] (https://github.com/UW-Hydro/VIC/pull/732) + + Updates the cesm_put_data.c routine in the CESM driver to include the correct units for sensible heat flux and updates the rofliq calculation to be correct (previously only OUT_BASEFLOW was being divided by global_param.dt). + + [GH#734] (https://github.com/UW-Hydro/VIC/pull/734) + + Updates the cesm_put_data.c routine in the CESM driver to include the correct signs for turbulent heat fluxes and evaporation. Previously we had switched the signs to agree with the image driver and they should instead be in accordance with the sign conventions for coupled models, which differ from those of land surface models. Also, eliminate populating the `l2x_Sl_ram1` field with aero_resist to agree with the VIC 4 implementation in RASM. + + [GH#739] (https://github.com/UW-Hydro/VIC/pull/739) + + Updates the cesm_put_data.c routine in the CESM driver to include the correct signs for the wind stresses and fixes a bug in calculating friction velocity (previously it was missing a square root). + + [GH#744](https://github.com/UW-Hydro/VIC/pull/744) + + Updates the cesm_interface_c.c routine to include missing timers and the VIC RUN timer in the CESM driver. + + [GH#746](https://github.com/UW-Hydro/VIC/pull/746) + + Updates the cesm_interface_c.c routine in the CESM driver to populate the nrecs, endyear, endmonth and endday fields in the global_param struct to make them available to vic_finalize for timing tables (specifically the secs/day columns). + +3. Speed up NetCDF operations in the image/CESM drivers ([GH#684](https://github.com/UW-Hydro/VIC/pull/684)) + + These changes speed up image driver initialization, forcing reads, and history writes by only opening and closing each input netCDF file once. + +4. Added two new timers to measure time in I/O operations ([GH#703](https://github.com/UW-Hydro/VIC/pull/703)) + + These two timers count the CPU and WALL time spent in ``vic_force`` and ``vic_write``. The accumulated time from these timers is printed out at the end of each simulation in the timing table. See also [GH#442](https://github.com/UW-Hydro/VIC/pull/442). + +5. Added gridcell-averaged albedo (STATE_AVG_ALBEDO) as a state file variable ([GH#712](https://github.com/UW-Hydro/VIC/pull/712)) + + This is for use in the CESM driver for VIC to pass to WRF, but has been implemented in the core structure of VIC (in vic_run) for consistency with the classic and image drivers. Running VIC from a cold start now also includes calculation of gridcell-averaged albedo. + +6. Cleanup of the initialization sections of the ``image`` and ``cesm`` drivers ([GH#701](https://github.com/UW-Hydro/VIC/pull/701)) + + Codified behavior in the initialization of the ``image`` and `cesm` drivers that requires the parameter variables `AreaFract`, `Pfactor`, `zone_fract`, and `Cv` must sum exactly to 1.0. If using the `SNOW_BAND` option, the area weighted `elevation` must match the mean grid cell elevation (`elev`). VIC will print *warnings* if any of these criteria are violated. + +7. Added thread parallelization using OPENMP ([GH#712](https://github.com/UW-Hydro/VIC/pull/712)) + + The VIC image and CESM drivers now may be optionally compiled with OPENMP to enable shared memory thread parallelization. This option should improve the parallel scaling of these drivers by reducing the number of MPI messages and increasing message size. + +#### Bug Fixes: + +1. Renamed "fcov" to "fcan" in image driver to better match variable code name ([GH#673](https://github.com/UW-Hydro/VIC/pull/673)) ------------------------------ @@ -50,10 +125,10 @@ To check which release of VIC you are running: 2. Fixed forceskip rounding bug ([GH#639](https://github.com/UW-Hydro/VIC/pull/639)) - After the fix, the `forceskip` variable in the global parameter structure (i.e., the number of timesteps to skip in the forcing data for the simulatin period) is rounded correctly (before the fix, rounding error might cause 1-timestep offset in the simulation results). + After the fix, the `forceskip` variable in the global parameter structure (i.e., the number of timesteps to skip in the forcing data for the simulation period) is rounded correctly (before the fix, rounding error might cause 1-timestep offset in the simulation results). 3. Fixed a problem with image restarts when using multiple processors ([GH#638](https://github.com/UW-Hydro/VIC/pull/638)) - + After the fix, only the master node is assigned the task of validating state file dimensions and coordinate variables. Multiprocessing was also added to the VIC testing framework. 4. Ensured that the mask variable in the input domain file must be integer type; otherwise an error is raised. ([GH#645](https://github.com/UW-Hydro/VIC/pull/645)) @@ -64,8 +139,8 @@ To check which release of VIC you are running: 6. Fixed a bug related to writing two-dimensional lat/lon variables to a state file ([GH#652](https://github.com/UW-Hydro/VIC/pull/652)) - Before the bug fix, two-dimensional lat/lon variables were not populated correctly and were written as fill values to a state file. Now two-dimensional lat/lon variables are correctly populated and written. - + Before the bug fix, two-dimensional lat/lon variables were not populated correctly and were written as fill values to a state file. Now two-dimensional lat/lon variables are correctly populated and written. + 7. Fixed a bug related to `dz_node` and `node_depth` variables in image driver output state file ([GH#657](https://github.com/UW-Hydro/VIC/pull/657)) Before the fix, `dz_node` and `node_depth` in image driver output state file were not spatially distributed, which was wrong. Now these two variables are spatially distributed in the output state file. @@ -82,7 +157,6 @@ To check which release of VIC you are running: Before the fix, there would be an error if the simulation start time is later than the forcing start time that year AND the simulation spans multiple years. Fixed this bug. - ------------------------------ ## VIC 5.0.0 [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.61422.svg)](http://dx.doi.org/10.5281/zenodo.61422) @@ -260,7 +334,6 @@ This is a major update from VIC 4. The VIC 5.0.0 release aims to have nearly ide 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.d [![DOI](https://zenodo.org/badge/doi/10.5281/zenodo.56058.svg)](http://dx.doi.org/10.5281/zenodo.56058) diff --git a/docs/Documentation/Drivers/Image/Params.md b/docs/Documentation/Drivers/Image/Params.md index 243904ba2..5be216247 100644 --- a/docs/Documentation/Drivers/Image/Params.md +++ b/docs/Documentation/Drivers/Image/Params.md @@ -2,6 +2,9 @@ The Image Driver uses the [NetCDF](http://www.unidata.ucar.edu/software/netcdf/) file format for its input model parameters. It is possible to convert the VIC ASCII style parameters to this format. We have put together an example ([Tutorial](Ascii_to_NetCDF_params.md) and [Ipython Notebook](https://github.com/UW-Hydro/VIC/blob/develop/samples/notebooks/example_reformat_vic4_parameters_to_vic5image.ipynb)) that provide examples of how to do this conversion. Our example uses the `tonic` [Python](https://www.python.org/) Package. +!!! Note + It is the user's responsibility to ensure that parameter files are formatted appropriately. Notably, the variables `AreaFract`, `Pfactor`, `zone_fract`, and `Cv` must sum exactly to 1.0. If using the `SNOW_BAND` option, the area weighted `elevation` must match the mean grid cell elevation (`elev`). VIC will print *** warnings *** if any of these criteria are violated. + # Soil Parameters The Soil Parameters serve three main purposes: diff --git a/docs/Documentation/Drivers/Image/RunVIC.md b/docs/Documentation/Drivers/Image/RunVIC.md index a88e588e2..a0e2bd6f2 100644 --- a/docs/Documentation/Drivers/Image/RunVIC.md +++ b/docs/Documentation/Drivers/Image/RunVIC.md @@ -19,6 +19,9 @@ The Image Driver has three dependencies: 3. [netCDF4](http://www.unidata.ucar.edu/software/netcdf/) +!!! Note + Compiling the Image Driver may also be done with [OpenMP](http://www.openmp.org/). Nearly all modern C compilers include the [OpenMP standard](http://www.openmp.org/resources/openmp-compilers/) and users will need to ensure that the makefile has the appropriate compiler flag (usually `-fopenmp`). See the discussion below for how to control OpenMP parallelization. + ## Compiling In most cases, you will need to edit the `NETCDF_PATH` and `MPI_PATH` variables in the `Makefile`. @@ -50,11 +53,23 @@ 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 processors, type the following instead: +The VIC image driver can be run using parallel processing with MPI and/or OpenMP. + +!!! Note + Users are encouraged to consult their system administrator for assistance in configuring the VIC image driver for parallel processing applications. + +To run VIC image driver using multiple processors using MPI, type the following instead: mpiexec -np $n_proc ./vic_image.exe -g global_parameter_filename.txt -where `n_proc` = number of processors to be used +where `n_proc` = number of processors to be used. *Note that different MPI implementations may use different names for the MPI executable such as: `mpirun`, `mpiexec_mpt`, or `mpiexec.hydra`*. + +To run the VIC image driver using multiple processors with OpenMP (threads), set the environment variable `OMP_NUM_THREADS`: + + export OMP_NUM_THREADS=8 + ./vic_image.exe -g global_parameter_filename.txt + +These two parallelization methods may also be combined using a Hybrid OpenMP/MPI approach. However, that configuration is usually machine, compiler, or scheduler dependent. ## Other Command Line Options diff --git a/tests/run_profiling.py b/tests/run_profiling.py index 9fb29bacb..2140ad87f 100755 --- a/tests/run_profiling.py +++ b/tests/run_profiling.py @@ -111,7 +111,96 @@ def log2_range(m): mpiexec_mpt -np ${BC_MPI_TASKS_ALLOC} $vic_exe -g $vic_global END=$(date +%s) DIFF=$(echo "$END - $START" | bc) -printf "%5s | %f\n" ${BC_MPI_TASKS_ALLOC} $DIFF >> $timing_table_file''')} +printf "%5s | %f\n" ${BC_MPI_TASKS_ALLOC} $DIFF >> $timing_table_file'''), + 'thunder': host_config(profile=[dict(select=1, mpiprocs=36), + dict(select=2, mpiprocs=36), + dict(select=3, mpiprocs=36), + dict(select=4, mpiprocs=36), + dict(select=5, mpiprocs=36), + dict(select=6, mpiprocs=36), + dict(select=8, mpiprocs=36), + dict(select=10, mpiprocs=36), + dict(select=12, mpiprocs=36)], + submit='qsub', mpiexec='mpiexec_mpt', + template='''#!/bin/bash +#!/bin/bash +#PBS -N VIC$i +#PBS -q standard +#PBS -A NPSCA07935242 +#PBS -l application=VIC +#PBS -l select=$select:ncpus=36:mpiprocs=$mpiprocs +#PBS -l walltime=35:00:00 +#PBS -j oe + +# Qsub template for AFRL THUNDER +# Scheduler: PBS + +module load netcdf-fortran/intel/4.4.2 + +START=$(date +%s) +mpiexec_mpt -np ${BC_MPI_TASKS_ALLOC} $vic_exe -g $vic_global +END=$(date +%s) +DIFF=$(echo "$END - $START" | bc) +printf "%5s | %f\n" ${BC_MPI_TASKS_ALLOC} $DIFF >> $timing_table_file'''), + 'gordon': host_config(profile=[dict(select=1, mpiprocs=32), + dict(select=2, mpiprocs=32), + dict(select=3, mpiprocs=32), + dict(select=4, mpiprocs=32), + dict(select=5, mpiprocs=32), + dict(select=6, mpiprocs=32), + dict(select=8, mpiprocs=32), + dict(select=10, mpiprocs=32), + dict(select=12, mpiprocs=32)], + submit='qsub', mpiexec='aprun', + template='''#!/bin/bash +#PBS -N VIC$i +#PBS -q frontier +#PBS -A NPSCA07935YF5 +#PBS -l application=VIC +#PBS -l select=$select:ncpus=32:mpiprocs=$mpiprocs +#PBS -l walltime=35:00:00 +#PBS -j oe + +# Qsub template for DSRC GORDON +# Scheduler: PBS + +module load cray-netcdf/4.3.2 + +START=$(date +%s) +aprun -n ${BC_MPI_TASKS_ALLOC} $vic_exe -g $vic_global +END=$(date +%s) +DIFF=$(echo "$END - $START" | bc) +printf "%5s | %f\n" ${BC_MPI_TASKS_ALLOC} $DIFF >> $timing_table_file'''), + 'cheyenne': host_config(profile=[dict(select=1, mpiprocs=36), + dict(select=2, mpiprocs=36), + dict(select=3, mpiprocs=36), + dict(select=4, mpiprocs=36), + dict(select=5, mpiprocs=36), + dict(select=6, mpiprocs=36), + dict(select=8, mpiprocs=36), + dict(select=10, mpiprocs=36), + dict(select=12, mpiprocs=36)], + submit='qsub', mpiexec='mpiexec_mpt', + template='''#!/bin/bash +#!/bin/bash +#PBS -N VIC$i +#PBS -q regular +#PBS -A P48500028 +#PBS -l select=$select:ncpus=36:mpiprocs=$mpiprocs +#PBS -l walltime=12:00:00 +#PBS -j oe +#PBS -m abe + +# Qsub template for UCAR CHEYENNE +# Scheduler: PBS + +START=$(date +%s) + +$mpiexec $vic_exe -g $vic_global +END=$(date +%s) +DIFF=$(echo "$END - $START" | bc) +printf "%5s | %f\n" ${BC_MPI_TASKS_ALLOC} $DIFF >> $timing_table_file''') +} OUT_WIDTH = 100 @@ -217,7 +306,8 @@ def run_scaling(args): run_string = template.safe_substitute( vic_exe=args.vic_exe, vic_global=args.global_param, - timing_table_file=args.timing, i=i, **kwargs) + timing_table_file=args.timing, i=i, + mpiexec=config.mpiexec, **kwargs) run_file = 'vic_{host}_{i}.sh'.format(host=args.host, i=i) with open(run_file, 'w') as f: f.write(run_string) diff --git a/tests/test_image_driver.py b/tests/test_image_driver.py index 1759e2e2f..4dcf7a09b 100644 --- a/tests/test_image_driver.py +++ b/tests/test_image_driver.py @@ -291,4 +291,5 @@ def check_mpi_states(state_basedir, list_n_proc): 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') + err_msg='States are not an exact match ' + 'for variable: {}'.format(var)) diff --git a/tests/test_restart.py b/tests/test_restart.py index 89dfbf84a..a66799157 100644 --- a/tests/test_restart.py +++ b/tests/test_restart.py @@ -260,7 +260,7 @@ def check_exact_restart_fluxes(result_basedir, driver, run_periods): for var in ds_full_run.data_vars: np.testing.assert_array_equal( ds[var].values, ds_full_run_split_period[var].values, - err_msg='Fluxes are not an exact match') + err_msg='Fluxes are not an exact match for %s' % var) def check_exact_restart_states(state_basedir, driver, run_periods, @@ -365,7 +365,7 @@ def check_exact_restart_states(state_basedir, driver, run_periods, np.testing.assert_array_equal(ds_states[var].values, ds_states_full_run[var].values, err_msg='states are not an ' - 'exact match') + 'exact match for %s' % var) def read_ascii_state(state_fname): diff --git a/vic/drivers/cesm/Makefile b/vic/drivers/cesm/Makefile index 1c5ecbf39..dbc95dd22 100644 --- a/vic/drivers/cesm/Makefile +++ b/vic/drivers/cesm/Makefile @@ -95,6 +95,7 @@ LIBRARY = -lm -L${NETCDFPATH}/lib -lnetcdf # Set compiler flags CFLAGS = ${INCLUDES} -ggdb -O0 -Wall -Wextra -fPIC \ + -fopenmp \ -DLOG_LVL=$(LOG_LVL) \ -DGIT_VERSION=\"$(GIT_VERSION)\" \ -DUSERNAME=\"$(USER)\" \ diff --git a/vic/drivers/cesm/cpl_mct/lnd_comp_mct.F90 b/vic/drivers/cesm/cpl_mct/lnd_comp_mct.F90 index 7173aa594..22a889cd4 100644 --- a/vic/drivers/cesm/cpl_mct/lnd_comp_mct.F90 +++ b/vic/drivers/cesm/cpl_mct/lnd_comp_mct.F90 @@ -415,7 +415,7 @@ SUBROUTINE lnd_final_mct(EClock, cdata, x2l, l2x, cdata_s, x2s, s2x) CHARACTER(len=*), PARAMETER :: subname = '(lnd_final_mct)' !--- clean up - errno = vic_cesm_final() + errno = vic_cesm_final(vclock) IF (errno /= 0) THEN CALL shr_sys_abort(subname//' ERROR: vic_cesm_final returned a errno /= 0') diff --git a/vic/drivers/cesm/include/vic_driver_cesm.h b/vic/drivers/cesm/include/vic_driver_cesm.h index f39097064..b883b3f79 100644 --- a/vic/drivers/cesm/include/vic_driver_cesm.h +++ b/vic/drivers/cesm/include/vic_driver_cesm.h @@ -157,8 +157,9 @@ typedef struct { bool l2x_vars_set; /** l2x set flag */ } l2x_data_struct; -void advance_time(void); +void advance_vic_time(void); void assert_time_insync(vic_clock *vclock, dmy_struct *dmy); +void finalize_cesm_time(vic_clock *vclock); void get_global_param(FILE *); void initialize_cesm_time(void); void initialize_l2x_data(void); @@ -171,21 +172,24 @@ void print_vic_clock(vic_clock *vclock); void print_x2l_data(x2l_data_struct *x2l); void read_rpointer_file(char *fname); unsigned short int start_type_from_char(char *start_str); -char *trim(char *str); +char *trimstr(char *str); void validate_filenames(filenames_struct *filenames); void validate_global_param(global_param_struct *global_param); void validate_options(option_struct *options); void vic_cesm_alloc(void); int vic_cesm_init_mpi(int MPI_COMM_VIC_F); int vic_cesm_init(vic_clock *vclock, case_metadata *cmeta); -int vic_cesm_final(void); +int vic_cesm_final(vic_clock *vclock); void vic_cesm_finalize(void); int vic_cesm_run(vic_clock *vclock); void vic_force(void); void vic_cesm_put_data(void); void vic_cesm_run_model(void); void vic_cesm_start(vic_clock *vclock, case_metadata *cmeta); -void vic_populate_model_state(char *runtype_str); +void vic_initialize_albedo(void); +void vic_initialize_lwup(void); +void vic_initialize_temperature(void); +void vic_populate_model_state(char *runtype_str, dmy_struct *dmy_current); void write_rpointer_file(char *fname); #endif diff --git a/vic/drivers/cesm/readme.md b/vic/drivers/cesm/readme.md index a7814946b..44f6077b3 100644 --- a/vic/drivers/cesm/readme.md +++ b/vic/drivers/cesm/readme.md @@ -42,10 +42,12 @@ The CESM driver for VIC can be built in two ways. git checkout develop # follow typical steps to build RASM + # NOTE: only set DEBUG flag to TRUE if running RI compset + # (it does not work with WRF) cd $HOME/rasm_vic5/scripts today=$(date +'%Y%m%d') - compset=RI - mach=spirit_intel + compset=RI # adjust for compset + mach=spirit_intel # adjust for machine case_name=vic5.${compset}.test.${today}a create_newcase -case ${case_name} -res w5a_a94 -compset ${compset} -mach ${mach} cd ${case_name} @@ -56,7 +58,7 @@ The CESM driver for VIC can be built in two ways. ``` ** Supported Machines ** - - [x] Spirit + - [x] Thunder - [x] Lightning - [x] Garnet - [ ] Copper *(Not currently supported by RASM)* diff --git a/vic/drivers/cesm/src/cesm_interface_c.c b/vic/drivers/cesm/src/cesm_interface_c.c index e5d1e500a..df4f0336c 100644 --- a/vic/drivers/cesm/src/cesm_interface_c.c +++ b/vic/drivers/cesm/src/cesm_interface_c.c @@ -94,18 +94,37 @@ vic_cesm_init(vic_clock *vclock, vic_init(); // populate model state, either using a cold start or from a restart file - vic_populate_model_state(trim(cmeta->starttype)); + vic_populate_model_state(trimstr(cmeta->starttype), &dmy_current); // initialize forcings + timer_start(&(global_timers[TIMER_VIC_FORCE])); vic_force(); + timer_stop(&(global_timers[TIMER_VIC_FORCE])); // initialize output structures vic_init_output(&dmy_current); + // initialize albedo + vic_initialize_albedo(); + + // initialize temperature + vic_initialize_temperature(); + + // initialize upwelling longwave + vic_initialize_lwup(); + + // 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])); // stop vic all timer timer_stop(&(global_timers[TIMER_VIC_ALL])); + // init vic run timer + timer_init(&(global_timers[TIMER_VIC_RUN])); return EXIT_SUCCESS; } @@ -120,14 +139,16 @@ vic_cesm_run(vic_clock *vclock) // continue vic all timer timer_continue(&(global_timers[TIMER_VIC_ALL])); - // start vic run timer - timer_start(&(global_timers[TIMER_VIC_RUN])); + // continue vic run timer + timer_continue(&(global_timers[TIMER_VIC_RUN])); // reset l2x fields initialize_l2x_data(); // read forcing data + timer_continue(&(global_timers[TIMER_VIC_FORCE])); vic_force(); + timer_stop(&(global_timers[TIMER_VIC_FORCE])); // run vic over the domain vic_image_run(&dmy_current); @@ -136,17 +157,21 @@ vic_cesm_run(vic_clock *vclock) vic_cesm_put_data(); // Write history files + timer_continue(&(global_timers[TIMER_VIC_WRITE])); vic_write_output(&dmy_current); + timer_stop(&(global_timers[TIMER_VIC_WRITE])); // advance the clock - advance_time(); + advance_vic_time(); assert_time_insync(vclock, &dmy_current); // if save: if (vclock->state_flag) { // write state file + debug("writing state file for timestep %zu", current); vic_store(&dmy_current, state_filename); write_rpointer_file(state_filename); + debug("finished storing state file: %s", state_filename) } // reset x2l fields @@ -164,12 +189,15 @@ vic_cesm_run(vic_clock *vclock) * @brief Finalize function for CESM driver *****************************************************************************/ int -vic_cesm_final() +vic_cesm_final(vic_clock *vclock) { // continue vic all timer timer_continue(&(global_timers[TIMER_VIC_ALL])); - // start vic run timer - timer_start(&(global_timers[TIMER_VIC_RUN])); + // start vic final timer + timer_start(&(global_timers[TIMER_VIC_FINAL])); + + // finalize time + finalize_cesm_time(vclock); // clean up vic_cesm_finalize(); @@ -178,8 +206,10 @@ vic_cesm_final() 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/cesm/src/cesm_interface_f.F90 b/vic/drivers/cesm/src/cesm_interface_f.F90 index 4cf07718d..df510caa8 100644 --- a/vic/drivers/cesm/src/cesm_interface_f.F90 +++ b/vic/drivers/cesm/src/cesm_interface_f.F90 @@ -89,10 +89,11 @@ END FUNCTION vic_cesm_run !> @brief Finalize Interface !-------------------------------------------------------------------------- INTERFACE - INTEGER(C_INT) FUNCTION vic_cesm_final() BIND(C, name='vic_cesm_final') + INTEGER(C_INT) FUNCTION vic_cesm_final(vclock) BIND(C, name='vic_cesm_final') USE, INTRINSIC :: ISO_C_BINDING USE vic_cesm_def_mod IMPLICIT NONE + TYPE(vic_clock), INTENT(in) :: vclock END FUNCTION vic_cesm_final END INTERFACE diff --git a/vic/drivers/cesm/src/cesm_put_data.c b/vic/drivers/cesm/src/cesm_put_data.c index e07eaf137..efb37311f 100644 --- a/vic/drivers/cesm/src/cesm_put_data.c +++ b/vic/drivers/cesm/src/cesm_put_data.c @@ -44,6 +44,7 @@ vic_cesm_put_data() extern global_param_struct global_param; extern option_struct options; extern parameters_struct param; + extern double ***out_data; bool IsWet = false; // TODO: add lake fraction bool overstory; @@ -63,14 +64,13 @@ vic_cesm_put_data() double wind_stress; double wind_stress_x; double wind_stress_y; - double evap; cell_data_struct cell; energy_bal_struct energy; snow_data_struct snow; veg_var_struct veg_var; for (i = 0; i < local_domain.ncells_active; i++) { - // Zero l2x vars (leave unused fields as MISSING values) + // Zero l2x vars l2x_vic[i].l2x_Sl_t = 0; l2x_vic[i].l2x_Sl_tref = 0; l2x_vic[i].l2x_Sl_qref = 0; @@ -80,7 +80,7 @@ vic_cesm_put_data() l2x_vic[i].l2x_Sl_anidf = 0; l2x_vic[i].l2x_Sl_snowh = 0; l2x_vic[i].l2x_Sl_u10 = 0; - // l2x_vic[i].l2x_Sl_ddvel = 0; + l2x_vic[i].l2x_Sl_ddvel = 0; l2x_vic[i].l2x_Sl_fv = 0; l2x_vic[i].l2x_Sl_ram1 = 0; l2x_vic[i].l2x_Sl_logz0 = 0; @@ -91,14 +91,83 @@ vic_cesm_put_data() l2x_vic[i].l2x_Fall_lwup = 0; l2x_vic[i].l2x_Fall_evap = 0; l2x_vic[i].l2x_Fall_swnet = 0; - // l2x_vic[i].l2x_Fall_fco2_lnd = 0; - // l2x_vic[i].l2x_Fall_flxdst1 = 0; - // l2x_vic[i].l2x_Fall_flxdst2 = 0; - // l2x_vic[i].l2x_Fall_flxdst3 = 0; - // l2x_vic[i].l2x_Fall_flxdst4 = 0; - // l2x_vic[i].l2x_Fall_flxvoc = 0; + l2x_vic[i].l2x_Fall_fco2_lnd = 0; + l2x_vic[i].l2x_Fall_flxdst1 = 0; + l2x_vic[i].l2x_Fall_flxdst2 = 0; + l2x_vic[i].l2x_Fall_flxdst3 = 0; + l2x_vic[i].l2x_Fall_flxdst4 = 0; + l2x_vic[i].l2x_Fall_flxvoc = 0; l2x_vic[i].l2x_Flrl_rofliq = 0; - // l2x_vic[i].l2x_Flrl_rofice = 0; + l2x_vic[i].l2x_Flrl_rofice = 0; + + // populate reference values + + // 10m wind, VIC: m/s, CESM: m/s + l2x_vic[i].l2x_Sl_u10 = out_data[i][OUT_WIND][0]; + + // 2m reference temperature, VIC: C, CESM: K + l2x_vic[i].l2x_Sl_tref = out_data[i][OUT_AIR_TEMP][0] + CONST_TKFRZ; + + // 2m reference specific humidity, VIC: kg/kg, CESM: g/g + l2x_vic[i].l2x_Sl_qref = CONST_EPS * + out_data[i][OUT_VP][0] / + out_data[i][OUT_PRESSURE][0]; + + // band-specific quantities + // note that these include a veg correction (AreaFactor) + // that is already in the put_data routine + + // temperature, VIC: K, CESM: K + l2x_vic[i].l2x_Sl_t = out_data[i][OUT_RAD_TEMP][0]; + + // albedo, VIC: fraction, CESM: fraction + // Note: VIC does not partition its albedo, thus all types are + // the same value + albedo = all_vars[i].gridcell_avg.avg_albedo; + + // albedo: direct, visible + l2x_vic[i].l2x_Sl_avsdr = albedo; + + // albedo: direct , near-ir + l2x_vic[i].l2x_Sl_anidr = albedo; + + // albedo: diffuse, visible + l2x_vic[i].l2x_Sl_avsdf = albedo; + + // albedo: diffuse, near-ir + l2x_vic[i].l2x_Sl_anidf = albedo; + + // snow height, VIC: mm, CESM: m + // convert to VIC units + l2x_vic[i].l2x_Sl_snowh = out_data[i][OUT_SWE][0] / MM_PER_M; + + // net shortwave, VIC: W/m2, CESM: W/m2 + l2x_vic[i].l2x_Fall_swnet = out_data[i][OUT_SWNET][0]; + + // longwave up, VIC: W/m2, CESM: W/m2 + // adjust sign for CESM sign convention + l2x_vic[i].l2x_Fall_lwup = -1 * + (out_data[i][OUT_LWDOWN][0] - + out_data[i][OUT_LWNET][0]); + + // turbulent heat fluxes + // Note: both are the opposite sign from image driver + // in accordance with the sign convention for coupled models + // latent heat, VIC: W/m2, CESM: W/m2 + l2x_vic[i].l2x_Fall_lat = -1 * out_data[i][OUT_LATENT][0]; + + // sensible heat, VIC: W/m2, CESM: W/m2 + l2x_vic[i].l2x_Fall_sen += -1 * out_data[i][OUT_SENSIBLE][0]; + + // evaporation, VIC: mm, CESM: kg m-2 s-1 + l2x_vic[i].l2x_Fall_evap += -1 * out_data[i][OUT_EVAP][0] / + global_param.dt; + + // lnd->rtm input fluxes + l2x_vic[i].l2x_Flrl_rofliq = (out_data[i][OUT_RUNOFF][0] + + out_data[i][OUT_BASEFLOW][0]) / + global_param.dt; + // running sum to make sure we get the full grid cell AreaFactorSum = 0; @@ -128,70 +197,7 @@ vic_cesm_put_data() } AreaFactorSum += AreaFactor; - // temperature - // CESM units: K - if (overstory && snow.snow && !(options.LAKES && IsWet)) { - rad_temp = energy.Tfoliage + CONST_TKFRZ; - } - else { - rad_temp = energy.Tsurf + CONST_TKFRZ; - } - l2x_vic[i].l2x_Sl_t += AreaFactor * rad_temp; - - // 2m reference temperature - // CESM units: K - l2x_vic[i].l2x_Sl_tref += AreaFactor * (force[i].air_temp[NR] + CONST_TKFRZ); - - // 2m reference specific humidity - // CESM units: g/g - l2x_vic[i].l2x_Sl_qref += AreaFactor * CONST_EPS * - force[i].vp[NR] / force[i].pressure[NR]; - - // Albedo Note: VIC does not partition its albedo, all returned - // values will be the same - - // albedo: direct, visible - // CESM units: unitless - // 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 (force[i].shortwave[NR] > 0.) { - albedo = AreaFactor * - (force[i].shortwave[NR] - energy.NetShortAtmos) / - force[i].shortwave[NR]; - } - else { - albedo = 0.; - } - l2x_vic[i].l2x_Sl_avsdr += albedo; - - // albedo: direct , near-ir - // CESM units: unitless - l2x_vic[i].l2x_Sl_anidr += albedo; - - // albedo: diffuse, visible - // CESM units: unitless - l2x_vic[i].l2x_Sl_avsdf += albedo; - - // albedo: diffuse, near-ir - // CESM units: unitless - l2x_vic[i].l2x_Sl_anidf += albedo; - - // snow height - // CESM units: m - l2x_vic[i].l2x_Sl_snowh += AreaFactor * snow.depth; - - // 10m wind - // CESM units: m/s - l2x_vic[i].l2x_Sl_u10 += AreaFactor * force[i].wind[NR]; - - // dry deposition velocities (optional) - // CESM units: ? - // l2x_vic[i].l2x_Sl_ddvel; - - // aerodynamical resistance - // CESM units: s/m + // aerodynamical resistance, VIC: s/m, CESM: s/m if (overstory) { aero_resist = cell.aero_resist[1]; } @@ -205,8 +211,6 @@ vic_cesm_put_data() aero_resist = param.HUGE_RESIST; } - l2x_vic[i].l2x_Sl_ram1 += AreaFactor * aero_resist; - // log z0 // CESM units: m if (snow.snow) { @@ -214,12 +218,13 @@ vic_cesm_put_data() roughness = soil_con[i].snow_rough; } else if (HasVeg) { - // bare soil roughness + // vegetation roughness roughness = veg_lib[i][veg_con[i][veg].veg_class].roughness[ dmy_current.month - 1]; } else { + // bare soil roughness roughness = soil_con[i].rough; } if (roughness < DBL_EPSILON) { @@ -230,13 +235,13 @@ vic_cesm_put_data() // wind stress, zonal // CESM units: N m-2 - wind_stress_x = -1 * force[i].density[NR] * + wind_stress_x = out_data[i][OUT_DENSITY][0] * 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 * force[i].density[NR] * + wind_stress_y = out_data[i][OUT_DENSITY][0] * x2l_vic[i].x2l_Sa_v / aero_resist; l2x_vic[i].l2x_Fall_tauy += AreaFactor * wind_stress_y; @@ -245,73 +250,14 @@ 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 / force[i].density[NR]); - - // latent heat flux - // CESM units: W m-2 - l2x_vic[i].l2x_Fall_lat += -1 * AreaFactor * energy.AtmosLatent; - - // sensible heat flux - // CESM units: W m-2 - l2x_vic[i].l2x_Fall_sen += -1 * AreaFactor * - energy.AtmosSensible; - - // upward longwave heat flux - // CESM units: W m-2 - l2x_vic[i].l2x_Fall_lwup += AreaFactor * - (force[i].longwave[NR] - - energy.NetLongAtmos); - - // evaporation water flux - // CESM units: kg m-2 s-1 - evap = 0.0; - for (index = 0; index < options.Nlayer; index++) { - evap += cell.layer[index].evap; - } - evap += snow.vapor_flux * MM_PER_M; - if (HasVeg) { - evap += snow.canopy_vapor_flux * MM_PER_M; - evap += veg_var.canopyevap; - } - l2x_vic[i].l2x_Fall_evap += -1 * AreaFactor * evap / - global_param.dt; - - // heat flux shortwave net - l2x_vic[i].l2x_Fall_swnet += AreaFactor * - (force[i].shortwave[NR] - - energy.NetShortAtmos); - - // co2 flux **For testing set to 0 - // l2x_vic[i].l2x_Fall_fco2_lnd; - - // dust flux size bin 1 - // l2x_vic[i].l2x_Fall_flxdst1; - - // dust flux size bin 2 - // l2x_vic[i].l2x_Fall_flxdst2; - - // dust flux size bin 3 - // l2x_vic[i].l2x_Fall_flxdst3; - - // dust flux size bin 4 - // l2x_vic[i].l2x_Fall_flxdst4; - - // MEGAN fluxes - // l2x_vic[i].l2x_Fall_flxvoc; - - // lnd->rtm input fluxes - l2x_vic[i].l2x_Flrl_rofliq += AreaFactor * - (cell.runoff + - cell.baseflow) / global_param.dt; - - // lnd->rtm input fluxes - // l2x_vic[i].l2x_Flrl_rofice; - - // vars set flag - l2x_vic[i].l2x_vars_set = true; + sqrt(wind_stress / + out_data[i][OUT_DENSITY][0]); } } + // set variables-set flag + l2x_vic[i].l2x_vars_set = true; + if (!assert_close_double(AreaFactorSum, 1., 0., 1e-3)) { log_warn("AreaFactorSum (%f) is not 1", AreaFactorSum); diff --git a/vic/drivers/cesm/src/display_current_settings.c b/vic/drivers/cesm/src/display_current_settings.c index 86351b418..029575613 100644 --- a/vic/drivers/cesm/src/display_current_settings.c +++ b/vic/drivers/cesm/src/display_current_settings.c @@ -262,11 +262,11 @@ display_current_settings(int mode) 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, "Domain file\t\t%s\n", filenames.domain.nc_filename); fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "Constants File\t\t%s\n", filenames.constants); - fprintf(LOG_DEST, "Parameters file\t\t%s\n", filenames.params); + fprintf(LOG_DEST, "Parameters file\t\t%s\n", filenames.params.nc_filename); if (options.BASEFLOW == ARNO) { fprintf(LOG_DEST, "BASEFLOW\t\tARNO\n"); } @@ -361,7 +361,8 @@ 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\t%s\n", + filenames.init_state.nc_filename); if (options.STATE_FORMAT == NETCDF3_CLASSIC) { fprintf(LOG_DEST, "STATE_FORMAT\t\tNETCDF3_CLASSIC\n"); } diff --git a/vic/drivers/cesm/src/get_global_param.c b/vic/drivers/cesm/src/get_global_param.c index 33068bd3e..89ab7c3c4 100644 --- a/vic/drivers/cesm/src/get_global_param.c +++ b/vic/drivers/cesm/src/get_global_param.c @@ -72,6 +72,14 @@ get_global_param(FILE *gp) sscanf(cmdstr, "%*s %s", flgstr); global_param.time_units = str_to_timeunits(flgstr); } + else if (strcasecmp("FULL_ENERGY", optstr) == 0) { + sscanf(cmdstr, "%*s %s", flgstr); + options.FULL_ENERGY = str_to_bool(flgstr); + if (options.FULL_ENERGY == false) { + log_warn("FULL_ENERGY is set to FALSE. Please double check " + "that this is the setting you intended."); + } + } else if (strcasecmp("FROZEN_SOIL", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); options.FROZEN_SOIL = str_to_bool(flgstr); @@ -247,7 +255,7 @@ get_global_param(FILE *gp) } else { options.INIT_STATE = true; - strcpy(filenames.init_state, flgstr); + strcpy(filenames.init_state.nc_filename, flgstr); } } // Define state file format @@ -279,13 +287,13 @@ get_global_param(FILE *gp) sscanf(cmdstr, "%*s %s", filenames.constants); } else if (strcasecmp("DOMAIN", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.domain); + sscanf(cmdstr, "%*s %s", filenames.domain.nc_filename); } else if (strcasecmp("DOMAIN_TYPE", optstr) == 0) { get_domain_type(cmdstr); } else if (strcasecmp("PARAMETERS", optstr) == 0) { - sscanf(cmdstr, "%*s %s", filenames.params); + sscanf(cmdstr, "%*s %s", filenames.params.nc_filename); } else if (strcasecmp("ARNO_PARAMS", optstr) == 0) { sscanf(cmdstr, "%*s %s", flgstr); @@ -386,8 +394,8 @@ get_global_param(FILE *gp) } } else if (strcasecmp("SNOW_BAND", optstr) == 0) { - sscanf(cmdstr, "%*s %s", flgstr); - if (str_to_bool(flgstr)) { + sscanf(cmdstr, "%*s %s", flgstr); + if (str_to_bool(flgstr)) { options.SNOW_BAND = SNOW_BAND_TRUE_BUT_UNSET; } } @@ -422,7 +430,7 @@ get_global_param(FILE *gp) ; // do nothing } else if (strcasecmp("AGGFREQ", optstr) == 0) { - ; // do nothing + ; // do nothing } else if (strcasecmp("OUTPUT_STEPS_PER_DAY", optstr) == 0) { ; // do nothing @@ -482,7 +490,7 @@ validate_filenames(filenames_struct *filenames) } // Validate parameter file information - if (strcmp(filenames->params, "MISSING") == 0) { + if (strcmp(filenames->params.nc_filename, "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\"."); diff --git a/vic/drivers/cesm/src/print_library_cesm.c b/vic/drivers/cesm/src/print_library_cesm.c index 1a562232f..6b7d04aae 100644 --- a/vic/drivers/cesm/src/print_library_cesm.c +++ b/vic/drivers/cesm/src/print_library_cesm.c @@ -41,7 +41,7 @@ print_vic_clock(vic_clock *vclock) vclock->current_dayseconds); fprintf(LOG_DEST, "\tstate_flag : %d\n", vclock->state_flag); fprintf(LOG_DEST, "\tstop_flag : %d\n", vclock->stop_flag); - fprintf(LOG_DEST, "\tcalendar : %s\n", trim(vclock->calendar)); + fprintf(LOG_DEST, "\tcalendar : %s\n", trimstr(vclock->calendar)); } /****************************************************************************** @@ -51,12 +51,12 @@ void print_case_metadata(case_metadata *cmeta) { fprintf(LOG_DEST, "case_metadata :\n"); - fprintf(LOG_DEST, "\tcaseid : %s\n", trim(cmeta->caseid)); - fprintf(LOG_DEST, "\tcasedesc : %s\n", trim(cmeta->casedesc)); - fprintf(LOG_DEST, "\tstarttype : %s\n", trim(cmeta->starttype)); - fprintf(LOG_DEST, "\tmodel_version : %s\n", trim(cmeta->model_version)); - fprintf(LOG_DEST, "\thostname : %s\n", trim(cmeta->hostname)); - fprintf(LOG_DEST, "\tusername : %s\n", trim(cmeta->username)); + fprintf(LOG_DEST, "\tcaseid : %s\n", trimstr(cmeta->caseid)); + fprintf(LOG_DEST, "\tcasedesc : %s\n", trimstr(cmeta->casedesc)); + fprintf(LOG_DEST, "\tstarttype : %s\n", trimstr(cmeta->starttype)); + fprintf(LOG_DEST, "\tmodel_version : %s\n", trimstr(cmeta->model_version)); + fprintf(LOG_DEST, "\thostname : %s\n", trimstr(cmeta->hostname)); + fprintf(LOG_DEST, "\tusername : %s\n", trimstr(cmeta->username)); } /****************************************************************************** diff --git a/vic/drivers/cesm/src/vic_cesm_init_library.c b/vic/drivers/cesm/src/vic_cesm_init_library.c index d1e4f2562..ab2b73d23 100644 --- a/vic/drivers/cesm/src/vic_cesm_init_library.c +++ b/vic/drivers/cesm/src/vic_cesm_init_library.c @@ -88,7 +88,7 @@ initialize_l2x_data(void) size_t i; - log_info("Setting all l2x fields to %f", SHR_CONST_SPVAL); + log_info("Initializing l2x_data_struct"); for (i = 0; i < local_domain.ncells_active; i++) { l2x_vic[i].l2x_Sl_t = SHR_CONST_SPVAL; @@ -122,3 +122,65 @@ initialize_l2x_data(void) l2x_vic[i].l2x_vars_set = true; } } + +/****************************************************************************** + * @brief Initialize albedo values in l2x_data_struct. + *****************************************************************************/ +void +vic_initialize_albedo(void) +{ + extern l2x_data_struct *l2x_vic; + extern domain_struct local_domain; + extern all_vars_struct *all_vars; + + size_t i; + + log_info("Initializing albedo values"); + + for (i = 0; i < local_domain.ncells_active; i++) { + l2x_vic[i].l2x_Sl_avsdr = all_vars[i].gridcell_avg.avg_albedo; + l2x_vic[i].l2x_Sl_anidr = all_vars[i].gridcell_avg.avg_albedo; + l2x_vic[i].l2x_Sl_avsdf = all_vars[i].gridcell_avg.avg_albedo; + l2x_vic[i].l2x_Sl_anidf = all_vars[i].gridcell_avg.avg_albedo; + } +} + +/***************************************************************************** + * @brief Initialize temperature in l2x_data_struct. + ****************************************************************************/ +void +vic_initialize_temperature(void) +{ + extern l2x_data_struct *l2x_vic; + extern domain_struct local_domain; + extern soil_con_struct *soil_con; + + size_t i; + + log_info("Initializing temperature"); + + for (i = 0; i < local_domain.ncells_active; i++) { + l2x_vic[i].l2x_Sl_t = soil_con[i].avg_temp + CONST_TKFRZ; + } +} + +/***************************************************************************** + * @brief Initialize upwelling longwave in l2x_data_struct. + ****************************************************************************/ +void +vic_initialize_lwup(void) +{ + extern l2x_data_struct *l2x_vic; + extern domain_struct local_domain; + extern parameters_struct param; + + size_t i; + + log_info("Initializing upwelling longwave"); + + for (i = 0; i < local_domain.ncells_active; i++) { + // adjust sign for CESM sign convention + l2x_vic[i].l2x_Fall_lwup = -1 * param.EMISS_GRND * CONST_STEBOL * pow( + l2x_vic[i].l2x_Sl_t, 4); + } +} diff --git a/vic/drivers/cesm/src/vic_cesm_start.c b/vic/drivers/cesm/src/vic_cesm_start.c index 5db95a782..e79ccb173 100644 --- a/vic/drivers/cesm/src/vic_cesm_start.c +++ b/vic/drivers/cesm/src/vic_cesm_start.c @@ -47,8 +47,8 @@ vic_cesm_start(vic_clock *vclock, if (mpi_rank == VIC_MPI_ROOT) { strcpy(filenames.global, GLOBALPARAM); - // assign case name to state file name - strncpy(filenames.statefile, trim(cmeta->caseid), + // assign case name to state file name + strncpy(filenames.statefile, trimstr(cmeta->caseid), sizeof(filenames.statefile)); // read global settings @@ -76,7 +76,7 @@ vic_cesm_start(vic_clock *vclock, global_param.nrecs = 1; // Calendar - global_param.calendar = str_to_calendar(trim(vclock->calendar)); + global_param.calendar = str_to_calendar(trimstr(vclock->calendar)); // set NR and NF NF = global_param.snow_steps_per_day / global_param.model_steps_per_day; if (NF == 1) { @@ -107,7 +107,7 @@ vic_cesm_start(vic_clock *vclock, * using free() etc. *****************************************************************************/ char * -trim(char *str) +trimstr(char *str) { char *end; diff --git a/vic/drivers/cesm/src/vic_cesm_time.c b/vic/drivers/cesm/src/vic_cesm_time.c index 2377f90a5..d7083e51f 100644 --- a/vic/drivers/cesm/src/vic_cesm_time.c +++ b/vic/drivers/cesm/src/vic_cesm_time.c @@ -60,13 +60,32 @@ initialize_cesm_time(void) // initialize numdate numdate = date2num(global_param.time_origin_num, &dmy_current, 0., global_param.calendar, global_param.time_units); + + num2date(global_param.time_origin_num, numdate, 0., global_param.calendar, + global_param.time_units, &dmy_current); +} + +/****************************************************************************** + * @brief Finalize cesm time + *****************************************************************************/ +void +finalize_cesm_time(vic_clock *vclock) +{ + extern size_t current; + extern global_param_struct global_param; + + // populate fields in global_param needed for timing tables + global_param.nrecs = current; + global_param.endyear = vclock->current_year; + global_param.endmonth = vclock->current_month; + global_param.endday = vclock->current_day; } /****************************************************************************** * @brief Advance one timestep *****************************************************************************/ void -advance_time(void) +advance_vic_time(void) { extern size_t current; extern dmy_struct dmy_current; diff --git a/vic/drivers/cesm/src/vic_force.c b/vic/drivers/cesm/src/vic_force.c index 616e809ee..6a368fe5c 100644 --- a/vic/drivers/cesm/src/vic_force.c +++ b/vic/drivers/cesm/src/vic_force.c @@ -45,6 +45,7 @@ vic_force(void) extern option_struct options; extern soil_con_struct *soil_con; extern veg_con_map_struct *veg_con_map; + extern veg_con_struct **veg_con; extern veg_hist_struct **veg_hist; extern veg_lib_struct **veg_lib; extern parameters_struct param; @@ -128,6 +129,8 @@ vic_force(void) for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: Pa // VIC units: Pa + // Note: Image Driver uses kPa inputs and + // converts to Pa force[i].pressure[j] = x2l_vic[i].x2l_Sa_pbot; } } @@ -136,7 +139,7 @@ vic_force(void) for (j = 0; j < NF; j++) { for (i = 0; i < local_domain.ncells_active; i++) { // CESM units: shum is specific humidity (g/g) - // VIC units: kPa + // VIC units: Pa force[i].vp[j] = q_to_vp(x2l_vic[i].x2l_Sa_shum, force[i].pressure[j]); } @@ -205,6 +208,14 @@ vic_force(void) for (j = 0; j < NF; j++) { // vapor pressure deficit force[i].vpd[j] = svp(force[i].air_temp[j]) - force[i].vp[j]; + if (force[i].vpd[j] < 0) { + log_warn("Vapor pressure deficit is %f which is < 0, " + "setting vapor pressure deficit to 0 and calculating " + "saturated vapor pressure using air temperature %f.", + force[i].vpd[j], force[i].air_temp[j]); + force[i].vpd[j] = 0; + force[i].vp[j] = svp(force[i].air_temp[j]); + } // photosynthetically active radiation // TODO: Add CARBON_SW2PAR back to the parameters structure // force[i].par[j] = param.CARBON_SW2PAR * force[i].shortwave[j]; @@ -261,15 +272,15 @@ vic_force(void) if (vidx != NODATA_VEG) { for (j = 0; j < NF; j++) { veg_hist[i][vidx].albedo[j] = - veg_lib[i][v].albedo[dmy_current.month - 1]; + veg_con[i][vidx].albedo[dmy_current.month - 1]; veg_hist[i][vidx].displacement[j] = - veg_lib[i][v].displacement[dmy_current.month - 1]; + veg_con[i][vidx].displacement[dmy_current.month - 1]; veg_hist[i][vidx].fcanopy[j] = - veg_lib[i][v].fcanopy[dmy_current.month - 1]; + veg_con[i][vidx].fcanopy[dmy_current.month - 1]; veg_hist[i][vidx].LAI[j] = - veg_lib[i][v].LAI[dmy_current.month - 1]; + veg_con[i][vidx].LAI[dmy_current.month - 1]; veg_hist[i][vidx].roughness[j] = - veg_lib[i][v].roughness[dmy_current.month - 1]; + veg_con[i][vidx].roughness[dmy_current.month - 1]; } // not the correct way to calculate average albedo, but leave // for now diff --git a/vic/drivers/cesm/src/vic_populate_model_state.c b/vic/drivers/cesm/src/vic_populate_model_state.c index 4281d034e..4eac3393f 100644 --- a/vic/drivers/cesm/src/vic_populate_model_state.c +++ b/vic/drivers/cesm/src/vic_populate_model_state.c @@ -30,7 +30,8 @@ * @brief This function handles tasks related to populating model state. *****************************************************************************/ void -vic_populate_model_state(char *runtype_str) +vic_populate_model_state(char *runtype_str, + dmy_struct *dmy_current) { extern all_vars_struct *all_vars; extern lake_con_struct *lake_con; @@ -51,7 +52,7 @@ vic_populate_model_state(char *runtype_str) // 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_rpointer_file(filenames.init_state.nc_filename); // set options.INIT_STATE to true since we have found a state file in // the rpointer file. @@ -69,7 +70,7 @@ vic_populate_model_state(char *runtype_str) // 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]); + veg_con[i], dmy_current); if (options.LAKES) { generate_default_lake_state(&(all_vars[i]), &(soil_con[i]), lake_con[i]); diff --git a/vic/drivers/classic/include/vic_driver_classic.h b/vic/drivers/classic/include/vic_driver_classic.h index 4ca25e1d6..85cfe0b6e 100644 --- a/vic/drivers/classic/include/vic_driver_classic.h +++ b/vic/drivers/classic/include/vic_driver_classic.h @@ -111,7 +111,7 @@ 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 *, - lake_con_struct); + lake_con_struct, dmy_struct *); void write_data(stream_struct *streams); void write_header(stream_struct **streams, dmy_struct *dmy); void write_model_state(all_vars_struct *, int, int, filep_struct *, diff --git a/vic/drivers/classic/src/vic_classic.c b/vic/drivers/classic/src/vic_classic.c index 4a2e7de4c..51be1d43d 100644 --- a/vic/drivers/classic/src/vic_classic.c +++ b/vic/drivers/classic/src/vic_classic.c @@ -121,10 +121,14 @@ main(int argc, initialize_time(); dmy = make_dmy(&global_param); + // Allocate memory for out_data + out_data = malloc(1 * sizeof(*out_data)); + check_alloc_status(out_data, "Memory allocation error."); + /** Set up output data structures **/ set_output_met_data_info(); // out_data is shape [ngridcells (1), N_OUTVAR_TYPES] - alloc_out_data(1, &out_data); + alloc_out_data(1, out_data); filep.globalparam = open_file(filenames.global, "r"); parse_output_info(filep.globalparam, &streams, &(dmy[0])); validate_streams(&streams); @@ -221,7 +225,7 @@ main(int argc, **************************************************/ vic_populate_model_state(&all_vars, filep, soil_con.gridcel, - &soil_con, veg_con, lake_con); + &soil_con, veg_con, lake_con, &(dmy[0])); /** Initialize the storage terms in the water and energy balances **/ initialize_save_data(&all_vars, &force[0], &soil_con, veg_con, diff --git a/vic/drivers/classic/src/vic_populate_model_state.c b/vic/drivers/classic/src/vic_populate_model_state.c index 20b0f2eba..cd7d7aeaf 100644 --- a/vic/drivers/classic/src/vic_populate_model_state.c +++ b/vic/drivers/classic/src/vic_populate_model_state.c @@ -44,7 +44,8 @@ vic_populate_model_state(all_vars_struct *all_vars, size_t cellnum, soil_con_struct *soil_con, veg_con_struct *veg_con, - lake_con_struct lake_con) + lake_con_struct lake_con, + dmy_struct *dmy_current) { extern option_struct options; @@ -87,7 +88,7 @@ vic_populate_model_state(all_vars_struct *all_vars, } else { // else generate a default state - generate_default_state(all_vars, soil_con, veg_con); + generate_default_state(all_vars, soil_con, veg_con, dmy_current); if (options.LAKES) { generate_default_lake_state(all_vars, soil_con, lake_con); } diff --git a/vic/drivers/image/Makefile b/vic/drivers/image/Makefile index a764a8d96..1403f5b2a 100644 --- a/vic/drivers/image/Makefile +++ b/vic/drivers/image/Makefile @@ -87,7 +87,8 @@ INCLUDES = -I ${DRIVERPATH}/include \ -I ${EXTPATH}/${ROUT}/include # Uncomment to include debugging information -CFLAGS = ${INCLUDES} ${NC_CFLAGS} -ggdb -O0 -Wall -Wextra -std=c99 \ +CFLAGS = ${INCLUDES} ${NC_CFLAGS} -ggdb -O0 -Wall -Wextra -std=c99 \ + -fopenmp \ -DLOG_LVL=$(LOG_LVL) \ -DGIT_VERSION=\"$(GIT_VERSION)\" \ -DUSERNAME=\"$(USER)\" \ diff --git a/vic/drivers/image/include/vic_driver_image.h b/vic/drivers/image/include/vic_driver_image.h index 0c64a2d39..25d828df7 100644 --- a/vic/drivers/image/include/vic_driver_image.h +++ b/vic/drivers/image/include/vic_driver_image.h @@ -39,6 +39,6 @@ void vic_force(void); void vic_image_init(void); void vic_image_finalize(); void vic_image_start(void); -void vic_populate_model_state(void); +void vic_populate_model_state(dmy_struct *dmy_current); #endif diff --git a/vic/drivers/image/src/check_save_state_flag.c b/vic/drivers/image/src/check_save_state_flag.c index d71099719..3b046df35 100644 --- a/vic/drivers/image/src/check_save_state_flag.c +++ b/vic/drivers/image/src/check_save_state_flag.c @@ -32,7 +32,8 @@ * current time step *****************************************************************************/ bool -check_save_state_flag(size_t current, dmy_struct *dmy_offset) +check_save_state_flag(size_t current, + dmy_struct *dmy_offset) { extern global_param_struct global_param; extern dmy_struct *dmy; diff --git a/vic/drivers/image/src/display_current_settings.c b/vic/drivers/image/src/display_current_settings.c index 275202a0f..4bf4f71f6 100644 --- a/vic/drivers/image/src/display_current_settings.c +++ b/vic/drivers/image/src/display_current_settings.c @@ -384,7 +384,8 @@ 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.nc_filename); + fprintf(LOG_DEST, "INIT_STATE\t\tTRUE\t%s\n", + filenames.init_state.nc_filename); if (options.STATE_FORMAT == NETCDF3_CLASSIC) { fprintf(LOG_DEST, "STATE_FORMAT\t\tNETCDF3_CLASSIC\n"); } diff --git a/vic/drivers/image/src/get_global_param.c b/vic/drivers/image/src/get_global_param.c index a63f13d24..67344cdee 100644 --- a/vic/drivers/image/src/get_global_param.c +++ b/vic/drivers/image/src/get_global_param.c @@ -803,7 +803,7 @@ get_global_param(FILE *gp) sprintf(filenames.forcing[1].nc_filename, "%s%4d.nc", filenames.f_path_pfx[1], global_param.startyear); status = nc_open(filenames.forcing[1].nc_filename, NC_NOWRITE, - &(filenames.forcing[1].nc_id)); + &(filenames.forcing[1].nc_id)); check_nc_status(status, "Error opening %s", filenames.forcing[1].nc_filename); get_forcing_file_info(¶m_set, 1); diff --git a/vic/drivers/image/src/vic_force.c b/vic/drivers/image/src/vic_force.c index be0c80017..1209335e0 100644 --- a/vic/drivers/image/src/vic_force.c +++ b/vic/drivers/image/src/vic_force.c @@ -282,7 +282,6 @@ vic_force(void) if (options.LAI_SRC == FROM_VEGHIST || options.FCAN_SRC == FROM_VEGHIST || options.ALB_SRC == FROM_VEGHIST) { - // global_param.forceoffset[1] resets every year since the met file restarts // every year // global_param.forceskip[1] should also reset to 0 after the first year @@ -336,14 +335,14 @@ vic_force(void) } } - // Partial veg cover fraction: fcov + // Partial veg cover fraction: fcan if (options.FCAN_SRC == FROM_VEGHIST) { for (j = 0; j < NF; j++) { d4start[0] = global_param.forceskip[1] + global_param.forceoffset[1] + j; for (v = 0; v < options.NVEGTYPES; v++) { d4start[1] = v; - get_scatter_nc_field_double(&(filenames.forcing[1]), "fcov", + get_scatter_nc_field_double(&(filenames.forcing[1]), "fcan", d4start, d4count, dvar); for (i = 0; i < local_domain.ncells_active; i++) { vidx = veg_con_map[i].vidx[v]; @@ -503,6 +502,7 @@ vic_force(void) // cleanup free(dvar); + free(t_offset); } /****************************************************************************** @@ -527,9 +527,12 @@ get_forcing_file_info(param_set_struct *param_set, dmy_struct nc_start_dmy; // read time info from netcdf file - get_nc_field_double(&(filenames.forcing[file_num]), "time", &start, &count, nc_times); - get_nc_var_attr(&(filenames.forcing[file_num]), "time", "units", &nc_unit_chars); - get_nc_var_attr(&(filenames.forcing[file_num]), "time", "calendar", &calendar_char); + get_nc_field_double(&(filenames.forcing[file_num]), "time", &start, &count, + nc_times); + get_nc_var_attr(&(filenames.forcing[file_num]), "time", "units", + &nc_unit_chars); + get_nc_var_attr(&(filenames.forcing[file_num]), "time", "calendar", + &calendar_char); // parse the calendar string and check to make sure it matches the global clock calendar = str_to_calendar(calendar_char); diff --git a/vic/drivers/image/src/vic_image.c b/vic/drivers/image/src/vic_image.c index 7b203af2a..2de22ace0 100644 --- a/vic/drivers/image/src/vic_image.c +++ b/vic/drivers/image/src/vic_image.c @@ -125,7 +125,7 @@ main(int argc, rout_init(); // Routing routine (extension) // populate model state, either using a cold start or from a restart file - vic_populate_model_state(); + vic_populate_model_state(&(dmy[0])); // initialize output structures vic_init_output(&(dmy[0])); @@ -144,13 +144,17 @@ main(int argc, // loop over all timesteps for (current = 0; current < global_param.nrecs; current++) { // read forcing data + timer_continue(&(global_timers[TIMER_VIC_FORCE])); vic_force(); + timer_stop(&(global_timers[TIMER_VIC_FORCE])); // run vic over the domain vic_image_run(&(dmy[current])); // Write history files + timer_continue(&(global_timers[TIMER_VIC_WRITE])); vic_write_output(&(dmy[current])); + timer_stop(&(global_timers[TIMER_VIC_WRITE])); // Write state file if (check_save_state_flag(current, &dmy_state)) { diff --git a/vic/drivers/image/src/vic_image_start.c b/vic/drivers/image/src/vic_image_start.c index 401df8162..5a2ee4f12 100644 --- a/vic/drivers/image/src/vic_image_start.c +++ b/vic/drivers/image/src/vic_image_start.c @@ -32,9 +32,9 @@ void vic_image_start(void) { - extern filep_struct filep; - extern filenames_struct filenames; - extern int mpi_rank; + extern filep_struct filep; + extern filenames_struct filenames; + extern int mpi_rank; // Initialize structures initialize_global_structures(); diff --git a/vic/drivers/image/src/vic_populate_model_state.c b/vic/drivers/image/src/vic_populate_model_state.c index d65f2852f..4ea9ab7db 100644 --- a/vic/drivers/image/src/vic_populate_model_state.c +++ b/vic/drivers/image/src/vic_populate_model_state.c @@ -36,7 +36,7 @@ * @brief This function handles tasks related to populating model state. *****************************************************************************/ void -vic_populate_model_state(void) +vic_populate_model_state(dmy_struct *dmy_current) { extern all_vars_struct *all_vars; extern lake_con_struct *lake_con; @@ -54,7 +54,8 @@ vic_populate_model_state(void) else { // else generate a default state for (i = 0; i < local_domain.ncells_active; i++) { - generate_default_state(&(all_vars[i]), &(soil_con[i]), veg_con[i]); + generate_default_state(&(all_vars[i]), &(soil_con[i]), veg_con[i], + dmy_current); if (options.LAKES) { generate_default_lake_state(&(all_vars[i]), &(soil_con[i]), lake_con[i]); diff --git a/vic/drivers/python/vic_build.py b/vic/drivers/python/vic_build.py index 730dad9ea..f8c243379 100644 --- a/vic/drivers/python/vic_build.py +++ b/vic/drivers/python/vic_build.py @@ -3,7 +3,7 @@ ffi = FFI() ffi.cdef(headers) -ffi.set_source('vic/_vic', None) +ffi.set_source('vic._vic', None) if __name__ == '__main__': ffi.compile() 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 0ba13bb93..4c3823980 100644 --- a/vic/drivers/shared_all/include/vic_driver_shared_all.h +++ b/vic/drivers/shared_all/include/vic_driver_shared_all.h @@ -45,6 +45,9 @@ // Default snow band setting #define SNOW_BAND_TRUE_BUT_UNSET 99999 +// Max counter for root distribution iteration +#define MAX_ROOT_ITER 9999 + /****************************************************************************** * @brief File formats *****************************************************************************/ @@ -356,6 +359,7 @@ enum STATE_LAKE_ICE_SNOW_PACK_WATER, /**< lake ice snow pack water: lake_var.pack_water */ STATE_LAKE_ICE_SNOW_ALBEDO, /**< lake ice snow albedo: lake_var.SAlbedo */ STATE_LAKE_ICE_SNOW_DEPTH, /**< lake ice snow depth: lake_var.sdepth */ + STATE_AVG_ALBEDO, /**< gridcell-averaged albedo: gridcell_avg.avg_albedo */ // 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_STATE_VARS /**< used as a loop counter*/ @@ -453,6 +457,8 @@ enum timers TIMER_VIC_INIT, TIMER_VIC_RUN, TIMER_VIC_FINAL, + TIMER_VIC_FORCE, + TIMER_VIC_WRITE, N_TIMERS }; @@ -584,7 +590,7 @@ void agg_stream_data(stream_struct *stream, dmy_struct *dmy_current, double all_30_day_from_dmy(dmy_struct *dmy); double all_leap_from_dmy(dmy_struct *dmy); void alloc_aggdata(stream_struct *stream); -void alloc_out_data(size_t ngridcells, double ****out_data); +void alloc_out_data(size_t ngridcells, double ***out_data); double average(double *ar, size_t n); double calc_energy_balance_error(double, double, double, double, double); void calc_root_fractions(veg_con_struct *veg_con, soil_con_struct *soil_con); @@ -628,7 +634,7 @@ void free_out_data(size_t ngridcells, double ***out_data); void free_streams(stream_struct **streams); void free_vegcon(veg_con_struct **veg_con); void generate_default_state(all_vars_struct *, soil_con_struct *, - veg_con_struct *); + veg_con_struct *, dmy_struct *); void generate_default_lake_state(all_vars_struct *, soil_con_struct *, lake_con_struct); void get_default_nstreams_nvars(size_t *nstreams, size_t nvars[]); diff --git a/vic/drivers/shared_all/src/calc_root_fraction.c b/vic/drivers/shared_all/src/calc_root_fraction.c index 87e7988d0..ff9efb9a1 100644 --- a/vic/drivers/shared_all/src/calc_root_fraction.c +++ b/vic/drivers/shared_all/src/calc_root_fraction.c @@ -42,6 +42,7 @@ calc_root_fractions(veg_con_struct *veg_con, size_t layer; size_t zone; size_t i; + size_t n_iter; double sum_fract; double dum; double Zstep; @@ -62,7 +63,16 @@ calc_root_fractions(veg_con_struct *veg_con, Zsum = 0; zone = 0; + n_iter = 0; while (zone < options.ROOT_ZONES) { + n_iter++; + if (n_iter > MAX_ROOT_ITER) { + log_warn("veg=%d of Nveg=%d", veg, Nveg); + log_warn("zone %zu of %zu ROOT_ZONES", zone, + options.ROOT_ZONES); + log_err("stuck in an infinite loop"); + } + Zstep = veg_con[veg].zone_depth[zone]; if ((Zsum + Zstep) <= Lsum && Zsum >= Lsum - Lstep) { /** CASE 1: Root Zone Completely in Soil Layer **/ @@ -124,6 +134,7 @@ calc_root_fractions(veg_con_struct *veg_con, } } else if (Zsum + Zstep > Lsum) { + zone++; if (layer < options.Nlayer) { veg_con[veg].root[layer] = sum_fract; sum_fract = 0.; diff --git a/vic/drivers/shared_all/src/generate_default_state.c b/vic/drivers/shared_all/src/generate_default_state.c index 7bb50f793..cfcda7dc7 100644 --- a/vic/drivers/shared_all/src/generate_default_state.c +++ b/vic/drivers/shared_all/src/generate_default_state.c @@ -34,7 +34,8 @@ void generate_default_state(all_vars_struct *all_vars, soil_con_struct *soil_con, - veg_con_struct *veg_con) + veg_con_struct *veg_con, + dmy_struct *dmy_current) { extern option_struct options; extern parameters_struct param; @@ -53,6 +54,10 @@ generate_default_state(all_vars_struct *all_vars, }; double Cv; double tmp; + double AreaFactor; + double TreeAdjustFactor = 1.; + double lakefactor = 1.; + double albedo_sum; double ***tmpT; double **tmpZ; int ErrorFlag; @@ -125,6 +130,32 @@ generate_default_state(all_vars_struct *all_vars, } } + + /************************************************************************ + Initialize gridcell-averaged albedo + ************************************************************************/ + // vegetation class-weighted albedo over gridcell + albedo_sum = 0; + for (veg = 0; veg <= Nveg; veg++) { + Cv = veg_con[veg].Cv; + if (Cv > 0) { + // TO-DO: account for treeline and lake factors + AreaFactor = (Cv * TreeAdjustFactor * lakefactor); + + if (veg != Nveg) { + // cold start, so using climatological albedo for all veg classes + // except for bare soil + albedo_sum += (AreaFactor * + veg_con[veg].albedo[dmy_current->month - 1]); + } + else { + // bare soil class, use bare soil albedo + albedo_sum += AreaFactor * param.ALBEDO_BARE_SOIL; + } + } + } + all_vars->gridcell_avg.avg_albedo = albedo_sum; + /************************************************************************ Initialize soil layer ice content ************************************************************************/ diff --git a/vic/drivers/shared_all/src/initialize_global.c b/vic/drivers/shared_all/src/initialize_global.c index b61457f7b..5bf50dc65 100644 --- a/vic/drivers/shared_all/src/initialize_global.c +++ b/vic/drivers/shared_all/src/initialize_global.c @@ -54,7 +54,7 @@ initialize_global() global_param.endyear = 0; global_param.endmonth = 0; global_param.endday = 0; - global_param.resolution = 0; + global_param.resolution = MISSING; global_param.wind_h = 10.0; for (i = 0; i < 2; i++) { global_param.forceyear[i] = 0; diff --git a/vic/drivers/shared_all/src/input_tools.c b/vic/drivers/shared_all/src/input_tools.c index 8f31e53bb..82e3d904f 100644 --- a/vic/drivers/shared_all/src/input_tools.c +++ b/vic/drivers/shared_all/src/input_tools.c @@ -150,6 +150,12 @@ str_to_out_type(char typestr[]) else if (strcasecmp("OUT_TYPE_SINT", typestr) == 0) { return OUT_TYPE_SINT; } + else if (strcasecmp("OUT_TYPE_INT", typestr) == 0) { + return OUT_TYPE_INT; + } + else if (strcasecmp("OUT_TYPE_CHAR", typestr) == 0) { + return OUT_TYPE_CHAR; + } else if (strcasecmp("OUT_TYPE_FLOAT", typestr) == 0) { return OUT_TYPE_FLOAT; } diff --git a/vic/drivers/shared_all/src/make_dmy.c b/vic/drivers/shared_all/src/make_dmy.c index 1b48cbdf0..ea113fd79 100644 --- a/vic/drivers/shared_all/src/make_dmy.c +++ b/vic/drivers/shared_all/src/make_dmy.c @@ -97,7 +97,7 @@ make_dmy(global_param_struct *global) global->forceskip[i] = (unsigned int) round((start_num - force_num) * - (double) param_set.force_steps_per_day[i]); + (double) param_set.force_steps_per_day[i]); } } diff --git a/vic/drivers/shared_all/src/print_library_shared.c b/vic/drivers/shared_all/src/print_library_shared.c index f6ae45509..ef9efdeaa 100644 --- a/vic/drivers/shared_all/src/print_library_shared.c +++ b/vic/drivers/shared_all/src/print_library_shared.c @@ -265,14 +265,15 @@ print_global_param(global_param_struct *gp) fprintf(LOG_DEST, "\tendmonth : %hu\n", gp->endmonth); fprintf(LOG_DEST, "\tendyear : %hu\n", gp->endyear); for (i = 0; i < 2; i++) { - fprintf(LOG_DEST, "\tforceday[%zd] : %hu\n", i, gp->forceday[i]); - fprintf(LOG_DEST, "\tforcesec[%zd] : %u\n", i, gp->forcesec[i]); - fprintf(LOG_DEST, "\tforcemonth[%zd] : %hu\n", i, + fprintf(LOG_DEST, "\tforceday[%zd] : %hu\n", i, gp->forceday[i]); + fprintf(LOG_DEST, "\tforcesec[%zd] : %u\n", i, gp->forcesec[i]); + fprintf(LOG_DEST, "\tforcemonth[%zd] : %hu\n", i, gp->forcemonth[i]); - fprintf(LOG_DEST, "\tforceoffset[%zd] : %hu\n", i, + fprintf(LOG_DEST, "\tforceoffset[%zd] : %hu\n", i, gp->forceoffset[i]); - fprintf(LOG_DEST, "\tforceskip[%zd] : %u\n", i, gp->forceskip[i]); - fprintf(LOG_DEST, "\tforceyear[%zd] : %hu\n", i, gp->forceyear[i]); + fprintf(LOG_DEST, "\tforceskip[%zd] : %u\n", i, gp->forceskip[i]); + fprintf(LOG_DEST, "\tforceyear[%zd] : %hu\n", i, + gp->forceyear[i]); } fprintf(LOG_DEST, "\tnrecs : %zu\n", gp->nrecs); fprintf(LOG_DEST, "\tstartday : %hu\n", gp->startday); @@ -434,64 +435,91 @@ print_option(option_struct *option) option->AboveTreelineVeg); fprintf(LOG_DEST, "\tAERO_RESIST_CANSNOW : %d\n", option->AERO_RESIST_CANSNOW); - fprintf(LOG_DEST, "\tBLOWING : %d\n", option->BLOWING); - fprintf(LOG_DEST, "\tBLOWING_VAR_THRESHOLD: %d\n", - option->BLOWING_VAR_THRESHOLD); - fprintf(LOG_DEST, "\tBLOWING_CALC_PROB : %d\n", - option->BLOWING_CALC_PROB); - fprintf(LOG_DEST, "\tBLOWING_SIMPLE : %d\n", option->BLOWING_SIMPLE); - fprintf(LOG_DEST, "\tBLOWING_FETCH : %d\n", option->BLOWING_FETCH); - fprintf(LOG_DEST, "\tBLOWING_SPATIAL_WIND : %d\n", - option->BLOWING_SPATIAL_WIND); - fprintf(LOG_DEST, "\tCARBON : %d\n", option->CARBON); - fprintf(LOG_DEST, "\tCLOSE_ENERGY : %d\n", option->CLOSE_ENERGY); - fprintf(LOG_DEST, "\tCOMPUTE_TREELINE : %d\n", - option->COMPUTE_TREELINE); - fprintf(LOG_DEST, "\tCONTINUEONERROR : %d\n", option->CONTINUEONERROR); - fprintf(LOG_DEST, "\tCORRPREC : %d\n", option->CORRPREC); - fprintf(LOG_DEST, "\tEQUAL_AREA : %d\n", option->EQUAL_AREA); - fprintf(LOG_DEST, "\tEXP_TRANS : %d\n", option->EXP_TRANS); - fprintf(LOG_DEST, "\tFROZEN_SOIL : %d\n", option->FROZEN_SOIL); - fprintf(LOG_DEST, "\tFULL_ENERGY : %d\n", option->FULL_ENERGY); + fprintf(LOG_DEST, "\tBLOWING : %s\n", + option->BLOWING ? "true" : "false"); + fprintf(LOG_DEST, "\tBLOWING_VAR_THRESHOLD: %s\n", + option->BLOWING_VAR_THRESHOLD ? "true" : "false"); + fprintf(LOG_DEST, "\tBLOWING_CALC_PROB : %s\n", + option->BLOWING_CALC_PROB ? "true" : "false"); + fprintf(LOG_DEST, "\tBLOWING_SIMPLE : %s\n", + option->BLOWING_SIMPLE ? "true" : "false"); + fprintf(LOG_DEST, "\tBLOWING_FETCH : %s\n", + option->BLOWING_FETCH ? "true" : "false"); + fprintf(LOG_DEST, "\tBLOWING_SPATIAL_WIND : %s\n", + option->BLOWING_SPATIAL_WIND ? "true" : "false"); + fprintf(LOG_DEST, "\tCARBON : %s\n", + option->CARBON ? "true" : "false"); + fprintf(LOG_DEST, "\tCLOSE_ENERGY : %s\n", + option->CLOSE_ENERGY ? "true" : "false"); + fprintf(LOG_DEST, "\tCOMPUTE_TREELINE : %s\n", + option->COMPUTE_TREELINE ? "true" : "false"); + fprintf(LOG_DEST, "\tCONTINUEONERROR : %s\n", + option->CONTINUEONERROR ? "true" : "false"); + fprintf(LOG_DEST, "\tCORRPREC : %s\n", + option->CORRPREC ? "true" : "false"); + fprintf(LOG_DEST, "\tEQUAL_AREA : %s\n", + option->EQUAL_AREA ? "true" : "false"); + fprintf(LOG_DEST, "\tEXP_TRANS : %s\n", + option->EXP_TRANS ? "true" : "false"); + fprintf(LOG_DEST, "\tFROZEN_SOIL : %s\n", + option->FROZEN_SOIL ? "true" : "false"); + fprintf(LOG_DEST, "\tFULL_ENERGY : %s\n", + option->FULL_ENERGY ? "true" : "false"); fprintf(LOG_DEST, "\tGRND_FLUX_TYPE : %d\n", option->GRND_FLUX_TYPE); - fprintf(LOG_DEST, "\tIMPLICIT : %d\n", option->IMPLICIT); - fprintf(LOG_DEST, "\tJULY_TAVG_SUPPLIED : %d\n", - option->JULY_TAVG_SUPPLIED); - fprintf(LOG_DEST, "\tLAKES : %d\n", option->LAKES); + fprintf(LOG_DEST, "\tIMPLICIT : %s\n", + option->IMPLICIT ? "true" : "false"); + fprintf(LOG_DEST, "\tJULY_TAVG_SUPPLIED : %s\n", + option->JULY_TAVG_SUPPLIED ? "true" : "false"); + fprintf(LOG_DEST, "\tLAKES : %s\n", + option->LAKES ? "true" : "false"); fprintf(LOG_DEST, "\tNcanopy : %zu\n", option->Ncanopy); fprintf(LOG_DEST, "\tNfrost : %zu\n", option->Nfrost); fprintf(LOG_DEST, "\tNlakenode : %zu\n", option->Nlakenode); fprintf(LOG_DEST, "\tNlayer : %zu\n", option->Nlayer); fprintf(LOG_DEST, "\tNnode : %zu\n", option->Nnode); - fprintf(LOG_DEST, "\tNOFLUX : %d\n", option->NOFLUX); + fprintf(LOG_DEST, "\tNOFLUX : %s\n", + option->NOFLUX ? "true" : "false"); fprintf(LOG_DEST, "\tNVEGTYPES : %zu\n", option->NVEGTYPES); fprintf(LOG_DEST, "\tRC_MODE : %d\n", option->RC_MODE); fprintf(LOG_DEST, "\tROOT_ZONES : %zu\n", option->ROOT_ZONES); - fprintf(LOG_DEST, "\tQUICK_FLUX : %d\n", option->QUICK_FLUX); - fprintf(LOG_DEST, "\tQUICK_SOLVE : %d\n", option->QUICK_SOLVE); - fprintf(LOG_DEST, "\tSHARE_LAYER_MOIST : %d\n", - option->SHARE_LAYER_MOIST); + fprintf(LOG_DEST, "\tQUICK_FLUX : %s\n", + option->QUICK_FLUX ? "true" : "false"); + fprintf(LOG_DEST, "\tQUICK_SOLVE : %s\n", + option->QUICK_SOLVE ? "true" : "false"); + fprintf(LOG_DEST, "\tSHARE_LAYER_MOIST : %s\n", + option->SHARE_LAYER_MOIST ? "true" : "false"); fprintf(LOG_DEST, "\tSNOW_DENSITY : %d\n", option->SNOW_DENSITY); fprintf(LOG_DEST, "\tSNOW_BAND : %zu\n", option->SNOW_BAND); - fprintf(LOG_DEST, "\tSPATIAL_FROST : %d\n", option->SPATIAL_FROST); - fprintf(LOG_DEST, "\tSPATIAL_SNOW : %d\n", option->SPATIAL_SNOW); - fprintf(LOG_DEST, "\tTFALLBACK : %d\n", option->TFALLBACK); + fprintf(LOG_DEST, "\tSPATIAL_FROST : %s\n", + option->SPATIAL_FROST ? "true" : "false"); + fprintf(LOG_DEST, "\tSPATIAL_SNOW : %s\n", + option->SPATIAL_SNOW ? "true" : "false"); + fprintf(LOG_DEST, "\tTFALLBACK : %s\n", + option->TFALLBACK ? "true" : "false"); fprintf(LOG_DEST, "\tBASEFLOW : %d\n", option->BASEFLOW); fprintf(LOG_DEST, "\tGRID_DECIMAL : %d\n", option->GRID_DECIMAL); - fprintf(LOG_DEST, "\tVEGLIB_PHOTO : %d\n", option->VEGLIB_PHOTO); - fprintf(LOG_DEST, "\tVEGLIB_FCAN : %d\n", option->VEGLIB_FCAN); - fprintf(LOG_DEST, "\tVEGPARAM_ALB : %d\n", option->VEGPARAM_ALB); - fprintf(LOG_DEST, "\tVEGPARAM_LAI : %d\n", option->VEGPARAM_LAI); - fprintf(LOG_DEST, "\tVEGPARAM_FCAN : %d\n", - option->VEGPARAM_FCAN); + fprintf(LOG_DEST, "\tVEGLIB_PHOTO : %s\n", + option->VEGLIB_PHOTO ? "true" : "false"); + fprintf(LOG_DEST, "\tVEGLIB_FCAN : %s\n", + option->VEGLIB_FCAN ? "true" : "false"); + fprintf(LOG_DEST, "\tVEGPARAM_ALB : %s\n", + option->VEGPARAM_ALB ? "true" : "false"); + fprintf(LOG_DEST, "\tVEGPARAM_LAI : %s\n", + option->VEGPARAM_LAI ? "true" : "false"); + fprintf(LOG_DEST, "\tVEGPARAM_FCAN : %s\n", + option->VEGPARAM_FCAN ? "true" : "false"); fprintf(LOG_DEST, "\tALB_SRC : %d\n", option->ALB_SRC); fprintf(LOG_DEST, "\tLAI_SRC : %d\n", option->LAI_SRC); fprintf(LOG_DEST, "\tFCAN_SRC : %d\n", option->FCAN_SRC); - fprintf(LOG_DEST, "\tLAKE_PROFILE : %d\n", option->LAKE_PROFILE); - fprintf(LOG_DEST, "\tORGANIC_FRACT : %d\n", option->ORGANIC_FRACT); + fprintf(LOG_DEST, "\tLAKE_PROFILE : %s\n", + option->LAKE_PROFILE ? "true" : "false"); + fprintf(LOG_DEST, "\tORGANIC_FRACT : %s\n", + option->ORGANIC_FRACT ? "true" : "false"); fprintf(LOG_DEST, "\tSTATE_FORMAT : %d\n", option->STATE_FORMAT); - fprintf(LOG_DEST, "\tINIT_STATE : %d\n", option->INIT_STATE); - fprintf(LOG_DEST, "\tSAVE_STATE : %d\n", option->SAVE_STATE); + fprintf(LOG_DEST, "\tINIT_STATE : %s\n", + option->INIT_STATE ? "true" : "false"); + fprintf(LOG_DEST, "\tSAVE_STATE : %s\n", + option->SAVE_STATE ? "true" : "false"); fprintf(LOG_DEST, "\tNoutstreams : %zu\n", option->Noutstreams); } @@ -817,17 +845,21 @@ print_snow_data(snow_data_struct *snow) fprintf(LOG_DEST, "\tdepth : %f\n", snow->depth); fprintf(LOG_DEST, "\tlast_snow : %d\n", snow->last_snow); fprintf(LOG_DEST, "\tmax_snow_depth : %f\n", snow->max_snow_depth); - fprintf(LOG_DEST, "\tMELTING : %d\n", snow->MELTING); + fprintf(LOG_DEST, "\tMELTING : %s\n", + snow->MELTING ? "true" : "false"); fprintf(LOG_DEST, "\tpack_temp : %f\n", snow->pack_temp); fprintf(LOG_DEST, "\tpack_water : %f\n", snow->pack_water); - fprintf(LOG_DEST, "\tsnow : %d\n", snow->snow); + fprintf(LOG_DEST, "\tsnow : %s\n", + snow->snow ? "true" : "false"); fprintf(LOG_DEST, "\tsnow_canopy : %f\n", snow->snow_canopy); fprintf(LOG_DEST, "\tstore_coverage : %f\n", snow->store_coverage); - fprintf(LOG_DEST, "\tstore_snow : %d\n", snow->store_snow); + fprintf(LOG_DEST, "\tstore_snow : %s\n", + snow->store_snow ? "true" : "false"); fprintf(LOG_DEST, "\tstore_swq : %f\n", snow->store_swq); fprintf(LOG_DEST, "\tsurf_temp : %f\n", snow->surf_temp); fprintf(LOG_DEST, "\tsurf_temp_fbcount : %u\n", snow->surf_temp_fbcount); - fprintf(LOG_DEST, "\tsurf_temp_fbflag : %d\n", snow->surf_temp_fbflag); + fprintf(LOG_DEST, "\tsurf_temp_fbflag : %s\n", + snow->surf_temp_fbflag ? "true" : "false"); fprintf(LOG_DEST, "\tsurf_water : %f\n", snow->surf_water); fprintf(LOG_DEST, "\tswq : %f\n", snow->swq); fprintf(LOG_DEST, "\tsnow_distrib_slope: %f\n", @@ -861,7 +893,8 @@ print_soil_con(soil_con_struct *scon, size_t j; fprintf(LOG_DEST, "soil_con:\n"); - fprintf(LOG_DEST, "\tFS_ACTIVE : %d\n", scon->FS_ACTIVE); + fprintf(LOG_DEST, "\tFS_ACTIVE : %s\n", + scon->FS_ACTIVE ? "true" : "false"); fprintf(LOG_DEST, "\tDs : %f\n", scon->Ds); fprintf(LOG_DEST, "\tDsmax : %f\n", scon->Dsmax); fprintf(LOG_DEST, "\tKsat :"); @@ -1041,7 +1074,7 @@ print_soil_con(soil_con_struct *scon, fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "AboveTreeLine :"); for (i = 0; i < nbands; i++) { - fprintf(LOG_DEST, "\t%d", scon->AboveTreeLine[i]); + fprintf(LOG_DEST, "\t%s", scon->AboveTreeLine[i] ? "true" : "false"); } fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, "\televation : %f\n", scon->elevation); @@ -1130,7 +1163,8 @@ print_veg_lib(veg_lib_struct *vlib, size_t i; fprintf(LOG_DEST, "veg_lib:\n"); - fprintf(LOG_DEST, "\toverstory : %d\n", vlib->overstory); + fprintf(LOG_DEST, "\toverstory : %s\n", + vlib->overstory ? "true" : "false"); fprintf(LOG_DEST, "\tLAI :"); for (i = 0; i < MONTHS_PER_YEAR; i++) { fprintf(LOG_DEST, "\t%.2f", vlib->LAI[i]); @@ -1181,7 +1215,8 @@ print_veg_lib(veg_lib_struct *vlib, fprintf(LOG_DEST, "\tMaxETransport : %.4f\n", vlib->MaxETransport); fprintf(LOG_DEST, "\tCO2Specificity: %.4f\n", vlib->CO2Specificity); fprintf(LOG_DEST, "\tLightUseEff : %.4f\n", vlib->LightUseEff); - fprintf(LOG_DEST, "\tNscaleFlag : %d\n", vlib->NscaleFlag); + fprintf(LOG_DEST, "\tNscaleFlag : %s\n", + vlib->NscaleFlag ? "true" : "false"); fprintf(LOG_DEST, "\tWnpp_inhib : %.4f\n", vlib->Wnpp_inhib); fprintf(LOG_DEST, "\tNPPfactor_sat : %.4f\n", vlib->NPPfactor_sat); } diff --git a/vic/drivers/shared_all/src/set_output_defaults.c b/vic/drivers/shared_all/src/set_output_defaults.c index 0b53d7a13..82c4769af 100644 --- a/vic/drivers/shared_all/src/set_output_defaults.c +++ b/vic/drivers/shared_all/src/set_output_defaults.c @@ -98,12 +98,12 @@ set_output_defaults(stream_struct **streams, dmy_struct *dmy_current, unsigned short default_file_format) { - extern option_struct options; + extern option_struct options; - size_t streamnum; - size_t varnum; - alarm_struct default_alarm; - int default_freq_n = 1; + size_t streamnum; + size_t varnum; + alarm_struct default_alarm; + int default_freq_n = 1; set_alarm(dmy_current, FREQ_NDAYS, &default_freq_n, &default_alarm); diff --git a/vic/drivers/shared_all/src/vic_history.c b/vic/drivers/shared_all/src/vic_history.c index 6a5278a21..c05ca8332 100644 --- a/vic/drivers/shared_all/src/vic_history.c +++ b/vic/drivers/shared_all/src/vic_history.c @@ -30,31 +30,22 @@ * @brief This routine creates the list of output data. *****************************************************************************/ void -alloc_out_data(size_t ngridcells, - double ****out_data) +alloc_out_data(size_t ngridcells, + double ***out_data) { extern metadata_struct out_metadata[N_OUTVAR_TYPES]; size_t i; size_t j; - size_t k; - - *out_data = calloc(ngridcells, sizeof(*(*out_data))); - check_alloc_status(*out_data, "Memory allocation error."); for (i = 0; i < ngridcells; i++) { - (*out_data)[i] = calloc(N_OUTVAR_TYPES, sizeof(*((*out_data)[i]))); - check_alloc_status((*out_data)[i], "Memory allocation error."); + out_data[i] = calloc(N_OUTVAR_TYPES, sizeof(*(out_data[i]))); + check_alloc_status(out_data[i], "Memory allocation error."); // Allocate space for data for (j = 0; j < N_OUTVAR_TYPES; j++) { - (*out_data)[i][j] = - calloc(out_metadata[j].nelem, sizeof(*((*out_data)[i][j]))); - check_alloc_status((*out_data)[i][j], "Memory allocation error."); - - // initialize data member - for (k = 0; k < out_metadata[j].nelem; k++) { - (*out_data)[i][j][k] = 0; - } + out_data[i][j] = + calloc(out_metadata[j].nelem, sizeof(*(out_data[i][j]))); + check_alloc_status(out_data[i][j], "Memory allocation error."); } } } diff --git a/vic/drivers/shared_all/src/vic_time.c b/vic/drivers/shared_all/src/vic_time.c index 0e57407ae..144fe742f 100644 --- a/vic/drivers/shared_all/src/vic_time.c +++ b/vic/drivers/shared_all/src/vic_time.c @@ -859,8 +859,8 @@ time_delta(dmy_struct *dmy_current, // if dmy_next.year is not leap year but date is Feb 29 !) make_lastday(global_param.calendar, dmy_next.year, lastday); dmy_next.day_in_year = 0; - for ( i = 0; i < MONTHS_PER_YEAR; i++ ) { - if ( (i+1) == dmy_next.month ) { + for (i = 0; i < MONTHS_PER_YEAR; i++) { + if ((i + 1) == dmy_next.month) { dmy_next.day_in_year += dmy_next.day; break; } 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 36708379e..01ccfe603 100644 --- a/vic/drivers/shared_image/include/vic_driver_shared_image.h +++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h @@ -34,6 +34,7 @@ #include #define MAXDIMS 10 +#define AREA_SUM_ERROR_THRESH 1e-20 /****************************************************************************** * @brief NetCDF file types @@ -175,7 +176,7 @@ typedef struct { typedef struct { nameid_struct forcing[MAX_FORCE_FILES]; /**< atmospheric forcing files */ char f_path_pfx[MAX_FORCE_FILES][MAXSTRING]; /**< path and prefix for - atmospheric forcing files */ + atmospheric forcing files */ char global[MAXSTRING]; /**< global control file name */ nameid_struct domain; /**< domain file name and nc_id*/ char constants[MAXSTRING]; /**< model constants file name */ diff --git a/vic/drivers/shared_image/include/vic_image_log.h b/vic/drivers/shared_image/include/vic_image_log.h index 151f2c191..2b650fbe8 100644 --- a/vic/drivers/shared_image/include/vic_image_log.h +++ b/vic/drivers/shared_image/include/vic_image_log.h @@ -66,7 +66,7 @@ #define check_nc_status(A, M, ...) if (A != NC_NOERR) {log_ncerr(A, M, \ ## __VA_ARGS__); \ errno = 0; exit( \ - EXIT_FAILURE); } + EXIT_FAILURE);} #define log_mpi_err(e, M, ...) print_trace(); \ print_mpi_error_str(e); fprintf(LOG_DEST, \ diff --git a/vic/drivers/shared_image/include/vic_mpi.h b/vic/drivers/shared_image/include/vic_mpi.h index e1f324d4a..c7366cb68 100644 --- a/vic/drivers/shared_image/include/vic_mpi.h +++ b/vic/drivers/shared_image/include/vic_mpi.h @@ -29,6 +29,11 @@ #include #include +#ifdef _OPENMP + #include +#else + #define omp_get_max_threads() 1 +#endif #define VIC_MPI_ROOT 0 @@ -37,7 +42,7 @@ *****************************************************************************/ typedef struct { char nc_filename[MAXSTRING]; - int nc_id; + int nc_id; } nameid_struct; void create_MPI_filenames_struct_type(MPI_Datatype *mpi_type); diff --git a/vic/drivers/shared_image/src/check_domain_info.c b/vic/drivers/shared_image/src/check_domain_info.c index 26d6ae26c..b32c0d00d 100644 --- a/vic/drivers/shared_image/src/check_domain_info.c +++ b/vic/drivers/shared_image/src/check_domain_info.c @@ -80,4 +80,5 @@ compare_ncdomain_with_global_domain(nameid_struct *nc_nameid) global_domain.locations[i].longitude, i); } } + free(ncfile_domain.locations); } diff --git a/vic/drivers/shared_image/src/get_global_domain.c b/vic/drivers/shared_image/src/get_global_domain.c index 4291b79d8..8d288ef7c 100644 --- a/vic/drivers/shared_image/src/get_global_domain.c +++ b/vic/drivers/shared_image/src/get_global_domain.c @@ -36,7 +36,7 @@ get_global_domain(nameid_struct *domain_nc_nameid, { int *run = NULL; int *mask = NULL; - int typeid; + int typeid; double *var = NULL; size_t i; size_t j; @@ -68,7 +68,8 @@ get_global_domain(nameid_struct *domain_nc_nameid, if (typeid != NC_INT) { log_err("Mask variable in the domain file must be integer type."); } - get_nc_field_int(domain_nc_nameid, global_domain->info.mask_var, d2start, d2count, + get_nc_field_int(domain_nc_nameid, global_domain->info.mask_var, d2start, + d2count, mask); // Get run_cell variable from the parameter file @@ -148,11 +149,11 @@ get_global_domain(nameid_struct *domain_nc_nameid, // free memory free(var); free(run); + free(mask); return global_domain->ncells_active; } - /****************************************************************************** * @brief Get lat and lon coordinates information from a netCDF file and store in nc_domain structure @@ -273,7 +274,8 @@ get_nc_latlon(nameid_struct *nc_nameid, * @brief Copy domain info from one domain structure to another *****************************************************************************/ void -copy_domain_info(domain_struct *domain_from, domain_struct *domain_to) +copy_domain_info(domain_struct *domain_from, + domain_struct *domain_to) { strcpy(domain_to->info.x_dim, domain_from->info.x_dim); strcpy(domain_to->info.y_dim, domain_from->info.y_dim); diff --git a/vic/drivers/shared_image/src/get_nc_field.c b/vic/drivers/shared_image/src/get_nc_field.c index 5b79f218e..cf3404122 100644 --- a/vic/drivers/shared_image/src/get_nc_field.c +++ b/vic/drivers/shared_image/src/get_nc_field.c @@ -31,10 +31,10 @@ *****************************************************************************/ int get_nc_field_double(nameid_struct *nc_nameid, - char *var_name, - size_t *start, - size_t *count, - double *var) + char *var_name, + size_t *start, + size_t *count, + double *var) { int status; int var_id; @@ -56,10 +56,10 @@ get_nc_field_double(nameid_struct *nc_nameid, *****************************************************************************/ int get_nc_field_float(nameid_struct *nc_nameid, - char *var_name, - size_t *start, - size_t *count, - float *var) + char *var_name, + size_t *start, + size_t *count, + float *var) { int status; int var_id; @@ -81,10 +81,10 @@ get_nc_field_float(nameid_struct *nc_nameid, *****************************************************************************/ int get_nc_field_int(nameid_struct *nc_nameid, - char *var_name, - size_t *start, - size_t *count, - int *var) + char *var_name, + size_t *start, + size_t *count, + int *var) { int status; int var_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 c16d24b50..4e1c07839 100644 --- a/vic/drivers/shared_image/src/get_nc_var_attr.c +++ b/vic/drivers/shared_image/src/get_nc_var_attr.c @@ -31,9 +31,9 @@ *****************************************************************************/ void get_nc_var_attr(nameid_struct *nc_nameid, - char *var_name, - char *attr_name, - char **attr) + char *var_name, + char *attr_name, + char **attr) { int var_id; int status; diff --git a/vic/drivers/shared_image/src/get_nc_var_type.c b/vic/drivers/shared_image/src/get_nc_var_type.c index 67dc4d5ad..d75586a2f 100644 --- a/vic/drivers/shared_image/src/get_nc_var_type.c +++ b/vic/drivers/shared_image/src/get_nc_var_type.c @@ -33,9 +33,9 @@ int get_nc_var_type(nameid_struct *nc_nameid, char *var_name) { - int var_id; - int status; - int xtypep; + int var_id; + int status; + int xtypep; // get variable id status = nc_inq_varid(nc_nameid->nc_id, var_name, &var_id); @@ -43,7 +43,8 @@ get_nc_var_type(nameid_struct *nc_nameid, nc_nameid->nc_filename); // get type ID - status = nc_inq_var(nc_nameid->nc_id, var_id, NULL, &xtypep, NULL, NULL, NULL); + status = nc_inq_var(nc_nameid->nc_id, var_id, NULL, &xtypep, NULL, NULL, + NULL); check_nc_status(status, "Error getting variable type %s in %s", var_name, nc_nameid->nc_filename); diff --git a/vic/drivers/shared_image/src/get_nc_varndimensions.c b/vic/drivers/shared_image/src/get_nc_varndimensions.c index de2eb5959..1f70b1adc 100644 --- a/vic/drivers/shared_image/src/get_nc_varndimensions.c +++ b/vic/drivers/shared_image/src/get_nc_varndimensions.c @@ -31,7 +31,7 @@ *****************************************************************************/ int get_nc_varndimensions(nameid_struct *nc_nameid, - char *var_name) + char *var_name) { int var_id; int ndims; diff --git a/vic/drivers/shared_image/src/parse_output_info.c b/vic/drivers/shared_image/src/parse_output_info.c index a9f0749a0..8977eb605 100644 --- a/vic/drivers/shared_image/src/parse_output_info.c +++ b/vic/drivers/shared_image/src/parse_output_info.c @@ -35,27 +35,27 @@ parse_output_info(FILE *gp, stream_struct **streams, dmy_struct *dmy_current) { - extern option_struct options; + 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; + 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; streamnum = -1; 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 c3d33fb0b..1872928ae 100644 --- a/vic/drivers/shared_image/src/print_library_shared_image.c +++ b/vic/drivers/shared_image/src/print_library_shared_image.c @@ -110,7 +110,7 @@ sprint_location(char *str, "\tlongitude : %.4f\n" "\tarea : %.4f\n" "\tfrac : %.4f\n" - "\nveg : %zd\n" + "\tnveg : %zd\n" "\tglobal_idx : %zd\n" "\tio_idx : %zd\n" "\tlocal_idx : %zd\n", diff --git a/vic/drivers/shared_image/src/state_metadata.c b/vic/drivers/shared_image/src/state_metadata.c index eaae28633..d235e681e 100644 --- a/vic/drivers/shared_image/src/state_metadata.c +++ b/vic/drivers/shared_image/src/state_metadata.c @@ -285,6 +285,17 @@ set_state_meta_data_info() strcpy(state_metadata[STATE_ENERGY_SNOW_FLUX].description, "thermal flux through snowpack"); + // STATE_GRIDCELL_AVG_ALBEDO + strcpy(state_metadata[STATE_AVG_ALBEDO].varname, + "STATE_AVG_ALBEDO"); + strcpy(state_metadata[STATE_AVG_ALBEDO].long_name, + "state_avg_albedo"); + strcpy(state_metadata[STATE_AVG_ALBEDO].standard_name, + "state_gridcell_avg_albedo"); + strcpy(state_metadata[STATE_AVG_ALBEDO].units, "fraction"); + strcpy(state_metadata[STATE_AVG_ALBEDO].description, + "gridcell averaged albedo"); + if (options.LAKES) { // STATE_LAKE_SOIL_MOISTURE strcpy(state_metadata[STATE_LAKE_SOIL_MOISTURE].varname, diff --git a/vic/drivers/shared_image/src/vic_alloc.c b/vic/drivers/shared_image/src/vic_alloc.c index 9c4a0b2cc..34ecfec9d 100644 --- a/vic/drivers/shared_image/src/vic_alloc.c +++ b/vic/drivers/shared_image/src/vic_alloc.c @@ -86,7 +86,7 @@ vic_alloc(void) check_alloc_status(out_data, "Memory allocation error."); // save_data allocation - save_data = malloc(local_domain.ncells_active * sizeof(*save_data)); + save_data = calloc(local_domain.ncells_active, sizeof(*save_data)); check_alloc_status(save_data, "Memory allocation error."); // allocate memory for individual grid cells diff --git a/vic/drivers/shared_image/src/vic_image_run.c b/vic/drivers/shared_image/src/vic_image_run.c index f8d7d8c09..06215c852 100644 --- a/vic/drivers/shared_image/src/vic_image_run.c +++ b/vic/drivers/shared_image/src/vic_image_run.c @@ -56,6 +56,8 @@ vic_image_run(dmy_struct *dmy_current) sprint_dmy(dmy_str, dmy_current); debug("Running timestep %zu: %s", current, dmy_str); + // If running with OpenMP, run this for loop using multiple threads + #pragma omp parallel for default(shared) private(i, timer, vic_run_ref_str) for (i = 0; i < local_domain.ncells_active; i++) { // Set global reference string (for debugging inside vic_run) sprintf(vic_run_ref_str, "Gridcell io_idx: %zu, timestep info: %s", diff --git a/vic/drivers/shared_image/src/vic_image_timing.c b/vic/drivers/shared_image/src/vic_image_timing.c index 39cf8ff11..e9b8a94a2 100644 --- a/vic/drivers/shared_image/src/vic_image_timing.c +++ b/vic/drivers/shared_image/src/vic_image_timing.c @@ -46,6 +46,8 @@ write_vic_timing_table(timer_struct *timers, struct passwd *pw; double ndays; double nyears; + int nprocs; + int nthreads; // datestr curr_date_time = time(NULL); @@ -70,6 +72,10 @@ write_vic_timing_table(timer_struct *timers, strcpy(user, "unknown"); } + // mpi/openmp + nthreads = omp_get_max_threads(); + nprocs = mpi_size * nthreads; + // calculate run length ndays = global_param.dt * global_param.nrecs / SEC_PER_DAY; nyears = ndays / DAYS_PER_YEAR; @@ -89,7 +95,8 @@ write_vic_timing_table(timer_struct *timers, 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.nc_filename); + fprintf(LOG_DEST, " Domain File : %s\n", + filenames.domain.nc_filename); fprintf(LOG_DEST, " Start Date : %04hu-%02hu-%02hu-%05u\n", global_param.startyear, global_param.startmonth, global_param.startday, global_param.startsec); @@ -106,7 +113,9 @@ write_vic_timing_table(timer_struct *timers, global_param.atmos_dt); fprintf(LOG_DEST, "\n"); - fprintf(LOG_DEST, " Total pes active : %d\n", mpi_size); + fprintf(LOG_DEST, " MPI Processes : %d\n", mpi_size); + fprintf(LOG_DEST, " OPENMP Threads : %d\n", nthreads); + fprintf(LOG_DEST, " Total pes active : %d\n", nprocs); fprintf(LOG_DEST, " pes per node : %ld\n", sysconf(_SC_NPROCESSORS_ONLN)); @@ -115,7 +124,7 @@ write_vic_timing_table(timer_struct *timers, 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 / + nprocs * 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)); @@ -146,6 +155,18 @@ write_vic_timing_table(timer_struct *timers, timers[TIMER_VIC_ALL].delta_cpu / ndays); fprintf(LOG_DEST, "|------------|----------------------|----------------------|----------------------|----------------------|\n"); + fprintf(LOG_DEST, "| Force Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_FORCE].delta_wall, + timers[TIMER_VIC_FORCE].delta_cpu, + timers[TIMER_VIC_FORCE].delta_wall / ndays, + timers[TIMER_VIC_FORCE].delta_cpu / ndays); + fprintf(LOG_DEST, "| Write Time | %20g | %20g | %20g | %20g |\n", + timers[TIMER_VIC_WRITE].delta_wall, + timers[TIMER_VIC_WRITE].delta_cpu, + timers[TIMER_VIC_WRITE].delta_wall / ndays, + timers[TIMER_VIC_WRITE].delta_cpu / ndays); + fprintf(LOG_DEST, + "|------------|----------------------|----------------------|----------------------|----------------------|\n"); fprintf(LOG_DEST, "\n"); fprintf(LOG_DEST, diff --git a/vic/drivers/shared_image/src/vic_init.c b/vic/drivers/shared_image/src/vic_init.c index 44fef6f5a..83a7cf769 100644 --- a/vic/drivers/shared_image/src/vic_init.c +++ b/vic/drivers/shared_image/src/vic_init.c @@ -576,7 +576,6 @@ vic_init(void) } } - // organic soils if (options.ORGANIC_FRACT) { // organic @@ -673,7 +672,8 @@ vic_init(void) // spatial snow if (options.SPATIAL_SNOW) { // max_snow_distrib_slope - get_scatter_nc_field_double(&(filenames.params), "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]; @@ -986,8 +986,7 @@ vic_init(void) } sum += soil_con[i].AreaFract[j]; } - // TBD: Need better check for equal to 1. - if (sum != 1.) { + if (!assert_close_double(sum, 1.0, 0., AREA_SUM_ERROR_THRESH)) { sprint_location(locstr, &(local_domain.locations[i])); log_warn("Sum of the snow band area fractions does not equal " "1 (%f), dividing each fraction by the sum\n%s", @@ -1002,7 +1001,8 @@ vic_init(void) for (j = 0; j < options.SNOW_BAND; j++) { mean += soil_con[i].BandElev[j] * soil_con[i].AreaFract[j]; } - if (fabs(soil_con[i].elevation - soil_con[i].BandElev[j]) > 1.0) { + if (!assert_close_double(soil_con[i].elevation, mean, 0., + AREA_SUM_ERROR_THRESH)) { sprint_location(locstr, &(local_domain.locations[i])); log_warn("average band elevation %f not equal to grid_cell " "average elevation %f; setting grid cell elevation " @@ -1040,8 +1040,7 @@ vic_init(void) } sum += soil_con[i].Pfactor[j]; } - // TBD: Need better check for equal to 1. - if (sum != 1.) { + if (!assert_close_double(sum, 1.0, 0., AREA_SUM_ERROR_THRESH)) { sprint_location(locstr, &(local_domain.locations[i])); log_warn("Sum of the snow band precipitation fractions does " "not equal 1 (%f), dividing each fraction by the " @@ -1190,8 +1189,7 @@ vic_init(void) for (k = 0; k < options.ROOT_ZONES; k++) { sum += veg_con[i][vidx].zone_fract[k]; } - // TBD: Need better test for not equal to 1. - if (sum != 1.) { + if (!assert_close_double(sum, 1.0, 0., AREA_SUM_ERROR_THRESH)) { sprint_location(locstr, &(local_domain.locations[i])); log_warn("Root zone fractions sum to more than 1 (%f), " "normalizing fractions. If the sum is large, " @@ -1229,11 +1227,16 @@ vic_init(void) // TODO: handle bare soil adjustment for compute treeline option - // If the sum of the tile fractions is not within a tolerance, throw an error - if (!assert_close_double(Cv_sum[i], 1., 0., 0.001)) { + // If the sum of the tile fractions is not within a tolerance, + // throw an error + if (!assert_close_double(Cv_sum[i], 1., 0., AREA_SUM_ERROR_THRESH)) { sprint_location(locstr, &(local_domain.locations[i])); - log_err("Cv != 1.0 (%f) at grid cell %zd. Exiting ...\n%s", - Cv_sum[i], i, locstr); + log_warn("Cv != 1.0 (%f) at grid cell %zd. Exiting ...\n%s", + Cv_sum[i], i, locstr); + for (j = 0; j < options.NVEGTYPES; j++) { + vidx = veg_con_map[i].vidx[j]; + veg_con[i][vidx].Cv /= Cv_sum[i]; + } } } @@ -1292,7 +1295,6 @@ vic_init(void) } } - // read_lake parameters if (options.LAKES) { // lake_idx diff --git a/vic/drivers/shared_image/src/vic_init_output.c b/vic/drivers/shared_image/src/vic_init_output.c index f8290e851..ecd3fd751 100644 --- a/vic/drivers/shared_image/src/vic_init_output.c +++ b/vic/drivers/shared_image/src/vic_init_output.c @@ -61,7 +61,7 @@ vic_init_output(dmy_struct *dmy_current) set_output_met_data_info(); // allocate out_data - alloc_out_data(local_domain.ncells_active, &out_data); + alloc_out_data(local_domain.ncells_active, out_data); // initialize the save data structures for (i = 0; i < local_domain.ncells_active; i++) { diff --git a/vic/drivers/shared_image/src/vic_mpi_support.c b/vic/drivers/shared_image/src/vic_mpi_support.c index 294131758..1cd8141f6 100644 --- a/vic/drivers/shared_image/src/vic_mpi_support.c +++ b/vic/drivers/shared_image/src/vic_mpi_support.c @@ -2043,10 +2043,10 @@ gather_put_nc_field_schar(int nc_id, *****************************************************************************/ void get_scatter_nc_field_double(nameid_struct *nc_nameid, - char *var_name, - size_t *start, - size_t *count, - double *var) + char *var_name, + size_t *start, + size_t *count, + double *var) { extern MPI_Comm MPI_COMM_VIC; extern domain_struct global_domain; @@ -2104,10 +2104,10 @@ get_scatter_nc_field_double(nameid_struct *nc_nameid, *****************************************************************************/ void get_scatter_nc_field_float(nameid_struct *nc_nameid, - char *var_name, - size_t *start, - size_t *count, - float *var) + char *var_name, + size_t *start, + size_t *count, + float *var) { extern MPI_Comm MPI_COMM_VIC; extern domain_struct global_domain; @@ -2167,10 +2167,10 @@ get_scatter_nc_field_float(nameid_struct *nc_nameid, *****************************************************************************/ void get_scatter_nc_field_int(nameid_struct *nc_nameid, - char *var_name, - size_t *start, - size_t *count, - int *var) + char *var_name, + size_t *start, + size_t *count, + int *var) { extern MPI_Comm MPI_COMM_VIC; extern domain_struct global_domain; diff --git a/vic/drivers/shared_image/src/vic_restore.c b/vic/drivers/shared_image/src/vic_restore.c index 30c189643..f5e850f43 100644 --- a/vic/drivers/shared_image/src/vic_restore.c +++ b/vic/drivers/shared_image/src/vic_restore.c @@ -477,6 +477,14 @@ vic_restore(void) } } + // grid cell-averaged albedo: gridcell_avg.avg_albedo + get_scatter_nc_field_double(&(filenames.init_state), + state_metadata[STATE_AVG_ALBEDO].varname, + d2start, d2count, dvar); + for (i = 0; i < local_domain.ncells_active; i++) { + all_vars[i].gridcell_avg.avg_albedo = dvar[i]; + } + // soil node temperatures: energy[veg][band].T[nidx] for (m = 0; m < options.NVEGTYPES; m++) { d5start[0] = m; @@ -934,12 +942,14 @@ check_init_state_file(void) // read and validate dimension lengths if (mpi_rank == VIC_MPI_ROOT) { - dimlen = get_nc_dimension(&(filenames.init_state), global_domain.info.x_dim); + dimlen = get_nc_dimension(&(filenames.init_state), + global_domain.info.x_dim); if (dimlen != global_domain.n_nx) { log_err("Number of grid columns in state file does not " "match parameter file"); } - dimlen = get_nc_dimension(&(filenames.init_state), global_domain.info.y_dim); + dimlen = get_nc_dimension(&(filenames.init_state), + global_domain.info.y_dim); if (dimlen != global_domain.n_ny) { log_err("Number of grid rows in state file does not " "match parameter file"); @@ -982,47 +992,55 @@ check_init_state_file(void) // lat/lon if (mpi_rank == VIC_MPI_ROOT) { - status = nc_inq_varid(filenames.init_state.nc_id, global_domain.info.lon_var, &lon_var_id); + status = nc_inq_varid(filenames.init_state.nc_id, + global_domain.info.lon_var, &lon_var_id); check_nc_status(status, "Unable to find variable \"%s\" in %s", - global_domain.info.lon_var, filenames.init_state.nc_filename); - status = nc_inq_varid(filenames.init_state.nc_id, global_domain.info.lat_var, &lat_var_id); + global_domain.info.lon_var, + filenames.init_state.nc_filename); + status = nc_inq_varid(filenames.init_state.nc_id, + global_domain.info.lat_var, &lat_var_id); check_nc_status(status, "Unable to find variable \"%s\" in %s", - global_domain.info.lat_var, filenames.init_state.nc_filename); + global_domain.info.lat_var, + filenames.init_state.nc_filename); if (global_domain.info.n_coord_dims == 1) { d1start[0] = 0; dvar = calloc(global_domain.n_nx, sizeof(*dvar)); check_alloc_status(dvar, "Memory allocation error"); - + d1count[0] = global_domain.n_nx; status = nc_get_vara_double(filenames.init_state.nc_id, lon_var_id, d1start, d1count, dvar); check_nc_status(status, "Error reading data from \"%s\" in %s", - global_domain.info.lon_var, filenames.init_state.nc_filename); + global_domain.info.lon_var, + filenames.init_state.nc_filename); // implicitly nested loop over ni and nj with j set to 0 for (i = 0; i < global_domain.n_nx; i++) { if (!assert_close_double(dvar[i], - global_domain.locations[i].longitude, rtol, + global_domain.locations[i].longitude, + rtol, abs_tol)) { log_err("Longitudes in initial state file do not " "match parameter file"); } } free(dvar); - + dvar = calloc(global_domain.n_ny, sizeof(*dvar)); check_alloc_status(dvar, "Memory allocation error"); - + d1count[0] = global_domain.n_ny; status = nc_get_vara_double(filenames.init_state.nc_id, lat_var_id, d1start, d1count, dvar); check_nc_status(status, "Error reading data from \"%s\" in %s", - global_domain.info.lat_var, filenames.init_state.nc_filename); + global_domain.info.lat_var, + filenames.init_state.nc_filename); // implicitly nested loop over ni and nj with i set to 0; // j stride = n_nx for (j = 0; j < global_domain.n_ny; j++) { if (!assert_close_double(dvar[j], global_domain.locations[j * - global_domain.n_nx] + global_domain. + n_nx] .latitude, rtol, abs_tol)) { log_err("Latitudes in initial state file do not " @@ -1034,15 +1052,17 @@ check_init_state_file(void) else if (global_domain.info.n_coord_dims == 2) { d2start[0] = 0; d2start[1] = 0; - dvar = calloc(global_domain.n_ny * global_domain.n_nx, sizeof(*dvar)); + dvar = + calloc(global_domain.n_ny * global_domain.n_nx, sizeof(*dvar)); check_alloc_status(dvar, "Memory allocation error"); - + d2count[0] = global_domain.n_ny; d2count[1] = global_domain.n_nx; status = nc_get_vara_double(filenames.init_state.nc_id, lon_var_id, d2start, d2count, dvar); check_nc_status(status, "Error reading data from \"%s\" in %s", - global_domain.info.lon_var, filenames.init_state.nc_filename); + global_domain.info.lon_var, + filenames.init_state.nc_filename); for (i = 0; i < global_domain.n_ny * global_domain.n_nx; i++) { if (dvar[i] != (double) global_domain.locations[i].longitude) { log_err("Longitudes in initial state file do not " @@ -1052,7 +1072,8 @@ check_init_state_file(void) status = nc_get_vara_double(filenames.init_state.nc_id, lat_var_id, d2start, d2count, dvar); check_nc_status(status, "Error reading data from \"%s\" in %s", - global_domain.info.lat_var, filenames.init_state.nc_filename); + global_domain.info.lat_var, + filenames.init_state.nc_filename); for (i = 0; i < global_domain.n_ny * global_domain.n_nx; i++) { if (dvar[i] != (double) global_domain.locations[i].latitude) { log_err("Latitudes in initial state file do not " diff --git a/vic/drivers/shared_image/src/vic_start.c b/vic/drivers/shared_image/src/vic_start.c index 8c36b216f..32cbc2c57 100644 --- a/vic/drivers/shared_image/src/vic_start.c +++ b/vic/drivers/shared_image/src/vic_start.c @@ -118,7 +118,8 @@ vic_start(void) 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"); + options.SNOW_BAND = get_nc_dimension(&(filenames.params), + "snow_band"); } if (options.LAKES) { options.NLAKENODES = get_nc_dimension(&(filenames.params), diff --git a/vic/drivers/shared_image/src/vic_store.c b/vic/drivers/shared_image/src/vic_store.c index 3fbde0144..d4a25eab4 100644 --- a/vic/drivers/shared_image/src/vic_store.c +++ b/vic/drivers/shared_image/src/vic_store.c @@ -740,6 +740,19 @@ vic_store(dmy_struct *dmy_state, } } + // Grid cell averaged albedo + nc_var = &(nc_state_file.nc_vars[STATE_AVG_ALBEDO]); + for (i = 0; i < local_domain.ncells_active; i++) { + dvar[i] = (double) all_vars[i].gridcell_avg.avg_albedo; + } + gather_put_nc_field_double(nc_state_file.nc_id, + nc_var->nc_varid, + nc_state_file.d_fillvalue, + d2start, nc_var->nc_counts, dvar); + for (i = 0; i < local_domain.ncells_active; i++) { + dvar[i] = nc_state_file.d_fillvalue; + } + if (options.LAKES) { // total soil moisture @@ -1281,6 +1294,7 @@ vic_store(dmy_struct *dmy_state, free(ivar); free(dvar); + free(nc_state_file.nc_vars); } /****************************************************************************** @@ -1450,6 +1464,15 @@ set_nc_state_var_info(nc_file_struct *nc) nc->nc_vars[i].nc_counts[3] = nc->nj_size; nc->nc_vars[i].nc_counts[4] = nc->ni_size; break; + case STATE_AVG_ALBEDO: + // 2d vars [j, i] + nc->nc_vars[i].nc_dims = 2; + nc->nc_vars[i].nc_dimids[0] = nc->nj_dimid; + nc->nc_vars[i].nc_dimids[1] = nc->ni_dimid; + nc->nc_vars[i].nc_counts[0] = nc->nj_size; + nc->nc_vars[i].nc_counts[1] = nc->ni_size; + break; + case STATE_LAKE_SOIL_MOISTURE: // 3d vars [layer, j, i] nc->nc_vars[i].nc_dims = 3; @@ -1598,16 +1621,19 @@ initialize_state_file(char *filename, check_nc_status(status, "Error setting fill value in %s", filename); // define the time dimension - status = nc_def_dim(nc_state_file->nc_id, "time", nc_state_file->time_size, + status = nc_def_dim(nc_state_file->nc_id, "time", + nc_state_file->time_size, &(nc_state_file->time_dimid)); - check_nc_status(status, "Error defining time dimenension in %s", filename); + check_nc_status(status, "Error defining time dimenension in %s", + filename); // define the variable time status = nc_def_var(nc_state_file->nc_id, "time", NC_DOUBLE, 1, &(nc_state_file->time_dimid), &(nc_state_file->time_varid)); check_nc_status(status, "Error defining time variable in %s", filename); - status = nc_put_att_text(nc_state_file->nc_id, nc_state_file->time_varid, + status = nc_put_att_text(nc_state_file->nc_id, + nc_state_file->time_varid, "standard_name", strlen("time"), "time"); check_nc_status(status, "Error adding attribute in %s", filename); @@ -1616,16 +1642,19 @@ initialize_state_file(char *filename, sprintf(str, "%s since %s", unit_str, global_param.time_origin_str); - status = nc_put_att_text(nc_state_file->nc_id, nc_state_file->time_varid, + status = nc_put_att_text(nc_state_file->nc_id, + nc_state_file->time_varid, "units", strlen(str), str); check_nc_status(status, "Error adding attribute in %s", filename); // adding calendar attribute to time variable str_from_calendar(global_param.calendar, str); - status = nc_put_att_text(nc_state_file->nc_id, nc_state_file->time_varid, + status = nc_put_att_text(nc_state_file->nc_id, + nc_state_file->time_varid, "calendar", strlen(str), str); - check_nc_status(status, "Error adding calendar attribute in %s", filename); + check_nc_status(status, "Error adding calendar attribute in %s", + filename); // define netcdf dimensions status = nc_def_dim(nc_state_file->nc_id, global_domain.info.x_dim, @@ -1641,7 +1670,8 @@ initialize_state_file(char *filename, filename); status = nc_def_dim(nc_state_file->nc_id, "veg_class", - nc_state_file->veg_size, &(nc_state_file->veg_dimid)); + nc_state_file->veg_size, + &(nc_state_file->veg_dimid)); check_nc_status(status, "Error defining veg_class in %s", filename); status = nc_def_dim(nc_state_file->nc_id, "snow_band", @@ -1767,7 +1797,8 @@ initialize_state_file(char *filename, strlen("veg_class"), "veg_class"); check_nc_status(status, "Error adding attribute in %s", filename); status = nc_put_att_text(nc_state_file->nc_id, veg_var_id, - "standard_name", strlen("vegetation_class_number"), + "standard_name", + strlen("vegetation_class_number"), "vegetation_class_number"); check_nc_status(status, "Error adding attribute in %s", filename); dimids[0] = -1; @@ -1794,8 +1825,10 @@ initialize_state_file(char *filename, status = nc_def_var(nc_state_file->nc_id, "layer", NC_INT, 1, dimids, &(layer_var_id)); - check_nc_status(status, "Error defining layer variable in %s", filename); - status = nc_put_att_text(nc_state_file->nc_id, layer_var_id, "long_name", + check_nc_status(status, "Error defining layer variable in %s", + filename); + status = nc_put_att_text(nc_state_file->nc_id, layer_var_id, + "long_name", strlen("layer"), "layer"); check_nc_status(status, "Error adding attribute in %s", filename); status = nc_put_att_text(nc_state_file->nc_id, layer_var_id, @@ -1827,7 +1860,8 @@ initialize_state_file(char *filename, status = nc_def_var(nc_state_file->nc_id, "dz_node", NC_DOUBLE, 3, dimids, &(dz_node_var_id)); check_nc_status(status, "Error defining node variable in %s", filename); - status = nc_put_att_text(nc_state_file->nc_id, dz_node_var_id, "long_name", + status = nc_put_att_text(nc_state_file->nc_id, dz_node_var_id, + "long_name", strlen("dz_node"), "dz_node"); check_nc_status(status, "Error adding attribute in %s", filename); status = nc_put_att_text(nc_state_file->nc_id, dz_node_var_id, @@ -1854,10 +1888,12 @@ initialize_state_file(char *filename, strlen("node_depth"), "node_depth"); check_nc_status(status, "Error adding attribute in %s", filename); status = nc_put_att_text(nc_state_file->nc_id, node_depth_var_id, - "standard_name", strlen("soil_thermal_node_depth"), + "standard_name", + strlen("soil_thermal_node_depth"), "soil_thermal_node_depth"); check_nc_status(status, "Error adding attribute in %s", filename); - status = nc_put_att_text(nc_state_file->nc_id, node_depth_var_id, "units", + status = nc_put_att_text(nc_state_file->nc_id, node_depth_var_id, + "units", strlen("m"), "m"); check_nc_status(status, "Error adding attribute in %s", filename); dimids[0] = -1; @@ -1869,13 +1905,15 @@ initialize_state_file(char *filename, dimids[0] = nc_state_file->lake_node_dimid; status = nc_def_var(nc_state_file->nc_id, "lake_node", NC_INT, 1, dimids, &(lake_node_var_id)); - check_nc_status(status, "Error defining node variable in %s", filename); + check_nc_status(status, "Error defining node variable in %s", + filename); status = nc_put_att_text(nc_state_file->nc_id, lake_node_var_id, "long_name", strlen("lake_node"), "lake_node"); check_nc_status(status, "Error adding attribute in %s", filename); status = nc_put_att_text(nc_state_file->nc_id, dz_node_var_id, - "standard_name", strlen("lake_node_number"), + "standard_name", strlen( + "lake_node_number"), "lake_node_number"); check_nc_status(status, "Error adding attribute in %s", filename); dimids[0] = -1; @@ -1921,13 +1959,17 @@ initialize_state_file(char *filename, state_metadata[i].varname, filename); // Set string attributes - put_nc_attr(nc_state_file->nc_id, nc_state_file->nc_vars[i].nc_varid, + put_nc_attr(nc_state_file->nc_id, + nc_state_file->nc_vars[i].nc_varid, "long_name", state_metadata[i].long_name); - put_nc_attr(nc_state_file->nc_id, nc_state_file->nc_vars[i].nc_varid, + put_nc_attr(nc_state_file->nc_id, + nc_state_file->nc_vars[i].nc_varid, "standard_name", state_metadata[i].standard_name); - put_nc_attr(nc_state_file->nc_id, nc_state_file->nc_vars[i].nc_varid, + put_nc_attr(nc_state_file->nc_id, + nc_state_file->nc_vars[i].nc_varid, "units", state_metadata[i].units); - put_nc_attr(nc_state_file->nc_id, nc_state_file->nc_vars[i].nc_varid, + put_nc_attr(nc_state_file->nc_id, + nc_state_file->nc_vars[i].nc_varid, "description", state_metadata[i].description); } @@ -1959,7 +2001,8 @@ initialize_state_file(char *filename, for (i = 0; i < nc_state_file->ni_size; i++) { dvar[i] = (double) global_domain.locations[i].longitude; } - status = nc_put_vara_double(nc_state_file->nc_id, lon_var_id, dstart, + status = nc_put_vara_double(nc_state_file->nc_id, lon_var_id, + dstart, dcount, dvar); check_nc_status(status, "Error adding data to lon in %s", filename); free(dvar); @@ -1976,7 +2019,8 @@ initialize_state_file(char *filename, latitude; } - status = nc_put_vara_double(nc_state_file->nc_id, lat_var_id, dstart, + status = nc_put_vara_double(nc_state_file->nc_id, lat_var_id, + dstart, dcount, dvar); check_nc_status(status, "Error adding data to lon in %s", filename); free(dvar); @@ -1990,7 +2034,8 @@ initialize_state_file(char *filename, for (i = 0; i < global_domain.ncells_total; i++) { dvar[i] = (double) global_domain.locations[i].longitude; } - status = nc_put_vara_double(nc_state_file->nc_id, lon_var_id, dstart, + status = nc_put_vara_double(nc_state_file->nc_id, lon_var_id, + dstart, dcount, dvar); check_nc_status(status, "Error adding data to lon in %s", filename); @@ -1998,7 +2043,8 @@ initialize_state_file(char *filename, i++) { dvar[i] = (double) global_domain.locations[i].latitude; } - status = nc_put_vara_double(nc_state_file->nc_id, lat_var_id, dstart, + status = nc_put_vara_double(nc_state_file->nc_id, lat_var_id, + dstart, dcount, dvar); check_nc_status(status, "Error adding data to lat in %s", filename); @@ -2022,7 +2068,8 @@ initialize_state_file(char *filename, for (j = 0; j < nc_state_file->veg_size; j++) { ivar[j] = (int) j + 1; } - status = nc_put_vara_int(nc_state_file->nc_id, veg_var_id, dstart, dcount, + status = nc_put_vara_int(nc_state_file->nc_id, veg_var_id, dstart, + dcount, ivar); check_nc_status(status, "Error writing veg var id"); for (i = 0; i < ndims; i++) { @@ -2058,7 +2105,8 @@ initialize_state_file(char *filename, for (j = 0; j < nc_state_file->layer_size; j++) { ivar[j] = (int) j; } - status = nc_put_vara_int(nc_state_file->nc_id, layer_var_id, dstart, dcount, + status = nc_put_vara_int(nc_state_file->nc_id, layer_var_id, dstart, + dcount, ivar); check_nc_status(status, "Error writing layer id"); for (i = 0; i < ndims; i++) { @@ -2076,7 +2124,8 @@ initialize_state_file(char *filename, for (j = 0; j < nc_state_file->frost_size; j++) { ivar[j] = (int) j; } - status = nc_put_vara_int(nc_state_file->nc_id, frost_area_var_id, dstart, + status = nc_put_vara_int(nc_state_file->nc_id, frost_area_var_id, + dstart, dcount, ivar); check_nc_status(status, "Error writing frost id"); for (i = 0; i < ndims; i++) { @@ -2135,6 +2184,7 @@ initialize_state_file(char *filename, dvar[i] = nc_state_file->d_fillvalue; } } + free(dvar); if (options.LAKES) { // lake nodes diff --git a/vic/vic_run/include/vic_def.h b/vic/vic_run/include/vic_def.h index 3a34ae711..184ede176 100644 --- a/vic/vic_run/include/vic_def.h +++ b/vic/vic_run/include/vic_def.h @@ -52,7 +52,7 @@ /***** Model Constants *****/ #define MAXSTRING 2048 #define MISSING -99999. /**< missing value */ -#define MISSING_USI 99999 /**< missing value for unsigned ints */ +#define MISSING_USI 99999. /**< missing value for unsigned ints */ #define MISSING_S "MISSING" /**< missing value for strings */ #define NODATA_VH -1 /**< missing value for veg_hist inputs */ #define NODATA_VEG -1 /**< flag for veg types not in grid cell */ @@ -268,7 +268,7 @@ typedef struct { Default = TRUE */ // input options - bool BASEFLOW; /**< ARNO: read Ds, Dm, Ws, c; NIJSSEN2001: read d1, d2, d3, d4 */ + unsigned short int BASEFLOW; /**< ARNO: read Ds, Dm, Ws, c; NIJSSEN2001: read d1, d2, d3, d4 */ unsigned short int GRID_DECIMAL; /**< Number of decimal places in grid file extensions */ bool VEGLIB_FCAN; /**< TRUE = veg library file contains monthly fcanopy values */ bool VEGLIB_PHOTO; /**< TRUE = veg library contains photosynthesis parameters */ @@ -999,6 +999,14 @@ typedef struct { condensation from snow pack (m) */ } snow_data_struct; +/****************************************************************************** + * @brief This structures stores variables averaged over a grid cell + *****************************************************************************/ +typedef struct { + // Grid cell averaged variables + double avg_albedo; /**< Average albedo over a grid cell */ +} gridcell_avg_struct; + /****************************************************************************** * @brief This structure stores the lake/wetland parameters for a grid cell *****************************************************************************/ @@ -1085,6 +1093,7 @@ typedef struct { lake_var_struct lake_var; /**< Stores lake/wetland variables */ snow_data_struct **snow; /**< Stores snow variables */ veg_var_struct **veg_var; /**< Stores vegetation variables */ + gridcell_avg_struct gridcell_avg; /**< Stores gridcell average variables */ } all_vars_struct; #endif diff --git a/vic/vic_run/include/vic_log.h b/vic/vic_run/include/vic_log.h index 819e17457..cfaf4a174 100644 --- a/vic/vic_run/include/vic_log.h +++ b/vic/vic_run/include/vic_log.h @@ -126,17 +126,17 @@ void setup_logging(int id, char log_path[], FILE **logfile); // here means that it just doesn't print a message, it still does the // check. MKAY? #define check_debug(A, M, ...) if (!(A)) {debug(M, ## __VA_ARGS__); errno = 0; \ - exit(EXIT_FAILURE); } + exit(EXIT_FAILURE);} #define check(A, M, ...) if (!(A)) {log_err(M, ## __VA_ARGS__); errno = 0; exit( \ - EXIT_FAILURE); } + EXIT_FAILURE);} #define check_alloc_status(A, M, \ ...) if (A == NULL) {log_err(M, ## __VA_ARGS__); \ errno = 0; exit( \ - EXIT_FAILURE); } + EXIT_FAILURE);} #define sentinel(M, ...) {log_err(M, ## __VA_ARGS__); errno = 0; exit( \ - EXIT_FAILURE); } + EXIT_FAILURE);} #define check_mem(A) check((A), "Out of memory.") @@ -144,7 +144,7 @@ void setup_logging(int id, char log_path[], FILE **logfile); E), E, __FUNCTION__, __LINE__) #define error_response(F, C, M, ...) {Response_send_status(F, &HTTP_ ## C); \ - sentinel(M, ## __VA_ARGS__); } + sentinel(M, ## __VA_ARGS__);} #define error_unless(T, F, C, M, ...) if (!(T)) \ error_response(F, C, M, ## __VA_ARGS__) diff --git a/vic/vic_run/include/vic_run.h b/vic/vic_run/include/vic_run.h index aba458c26..02ae0c073 100644 --- a/vic/vic_run/include/vic_run.h +++ b/vic/vic_run/include/vic_run.h @@ -49,6 +49,9 @@ double calc_atmos_energy_bal(double, double, double, double, double, double, double, double *, double *, double *, double *, double *, double *, bool *, unsigned int*); double calc_density(double); +void calc_gridcell_avg_albedo(double *, double, size_t, bool, + energy_bal_struct **, snow_data_struct **, + veg_con_struct *, soil_con_struct *); double calc_latent_heat_of_sublimation(double temp); double calc_latent_heat_of_vaporization(double temp); int calc_layer_average_thermal_props(energy_bal_struct *, layer_data_struct *, diff --git a/vic/vic_run/src/CalcBlowingSnow.c b/vic/vic_run/src/CalcBlowingSnow.c index 84357919d..16cfa6f97 100644 --- a/vic/vic_run/src/CalcBlowingSnow.c +++ b/vic/vic_run/src/CalcBlowingSnow.c @@ -377,9 +377,13 @@ trapzd(double (*funcd)(), double b, int n) { - double x, tnm, sum, del; + double x, tnm, sum, del; + int it, j; + + // TODO: remove use of static variables (see GH #735), for now: + // make static variables thread safe static double s; - int it, j; + #pragma omp threadprivate(s) if (n == 1) { return (s = 0.5 * diff --git a/vic/vic_run/src/calc_gridcell_avg_albedo.c b/vic/vic_run/src/calc_gridcell_avg_albedo.c new file mode 100644 index 000000000..e2ff2f2cc --- /dev/null +++ b/vic/vic_run/src/calc_gridcell_avg_albedo.c @@ -0,0 +1,101 @@ +/****************************************************************************** + * @section DESCRIPTION + * + * This routine computes gridcell-averaged albedo. + * + * Note: this routine is specifically designed for the CESM driver, for WRF, + * but has been implemented in other drivers as well for the sake of consistency. + * + * @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 Compute gridcell-averaged albedo. + *****************************************************************************/ +void +calc_gridcell_avg_albedo(double *albedo, + double shortwave, + size_t Nveg, + bool overstory, + energy_bal_struct **energy, + snow_data_struct **snow, + veg_con_struct *veg_con, + soil_con_struct *soil_con) +{ + extern option_struct options; + size_t veg; + size_t band; + double Cv; + double AreaFactor; + double TreeAdjustFactor = 1.; + double lakefactor = 1; + double swnet; + + swnet = 0; + *albedo = 0; + + for (veg = 0; veg <= Nveg; veg++) { + Cv = veg_con[veg].Cv; + if (Cv > 0) { + for (band = 0; band < options.SNOW_BAND; band++) { + if (soil_con->AreaFract[band] > 0.) { + // TO-DO: account for treeline and lake factors + AreaFactor = (Cv * soil_con->AreaFract[band] * + TreeAdjustFactor * lakefactor); + swnet += AreaFactor * energy[veg][band].NetShortAtmos; + } + } + } + } + + // compute gridcell-averaged albedo using average shortwave + if (shortwave > 0) { + // use average shortwave for albedo calculation + *albedo = 1. - (swnet / shortwave); + } + else { + // use vegetation, snow or bare soil albedo + for (veg = 0; veg <= Nveg; veg++) { + Cv = veg_con[veg].Cv; + if (Cv > 0) { + for (band = 0; band < options.SNOW_BAND; band++) { + if (soil_con->AreaFract[band] > 0.) { + // TO-DO: account for treeline and lake factors + AreaFactor = (Cv * soil_con->AreaFract[band] * + TreeAdjustFactor * lakefactor); + if (snow[veg][band].snow && overstory) { + // use snow canopy albedo + *albedo += AreaFactor * + energy[veg][band].AlbedoOver; + } + else { + // use surface albedo + *albedo += AreaFactor * + energy[veg][band].AlbedoUnder; + } + } + } + } + } + } +} diff --git a/vic/vic_run/src/frozen_soil.c b/vic/vic_run/src/frozen_soil.c index 1fc113bc4..90d6c09dc 100644 --- a/vic/vic_run/src/frozen_soil.c +++ b/vic/vic_run/src/frozen_soil.c @@ -170,16 +170,18 @@ solve_T_profile(double *T, int NOFLUX, int EXP_TRANS) { + double *aa, *bb, *cc, *dd, *ee, Bexp; + int Error; + int j; + + // TODO: remove use of static variables (see GH #735), for now: + // make static variables thread safe static double A[MAX_NODES]; static double B[MAX_NODES]; static double C[MAX_NODES]; static double D[MAX_NODES]; static double E[MAX_NODES]; - - double *aa, *bb, *cc, *dd, *ee, Bexp; - - int Error; - int j; + #pragma omp threadprivate(A, B, C, D, E) if (FIRST_SOLN[0]) { if (EXP_TRANS) { @@ -646,6 +648,18 @@ fda_heat_eqn(double T_2[], int init, ...) { + char PAST_BOTTOM; + double storage_term, flux_term, phase_term, flux_term1, flux_term2; + double Lsum; + int i; + size_t lidx; + int focus, left, right; + + // argument list handling + va_list arg_addr; + + // TODO: remove use of static variables (see GH #735), for now: + // make static variables thread safe static double deltat; static int NOFLUX; static int EXP_TRANS; @@ -681,15 +695,12 @@ fda_heat_eqn(double T_2[], static double DT[MAX_NODES], DT_down[MAX_NODES], DT_up[MAX_NODES]; static double Dkappa[MAX_NODES]; static double Bexp; - char PAST_BOTTOM; - double storage_term, flux_term, phase_term, flux_term1, flux_term2; - double Lsum; - int i; - size_t lidx; - int focus, left, right; - // argument list handling - va_list arg_addr; + #pragma omp threadprivate(deltat, NOFLUX, EXP_TRANS, T0, moist, ice, \ + kappa, Cs, max_moist, bubble, expt, alpha, beta, gamma, Zsum, Dp, \ + bulk_dens_min, soil_dens_min, quartz, bulk_density, soil_density, organic, \ + depth, Nlayers, Ts, Tb, ice_new, Cs_new, kappa_new, DT, DT_down, DT_up, \ + Dkappa, Bexp) // initialize variables if init==1 if (init == 1) { diff --git a/vic/vic_run/src/func_canopy_energy_bal.c b/vic/vic_run/src/func_canopy_energy_bal.c index 5f5a9d066..030e3c796 100644 --- a/vic/vic_run/src/func_canopy_energy_bal.c +++ b/vic/vic_run/src/func_canopy_energy_bal.c @@ -217,7 +217,7 @@ func_canopy_energy_bal(double Tfoliage, /* Calculate the latent heat flux */ Ls = calc_latent_heat_of_sublimation(Tfoliage); - *LatentHeatSub = Ls * *VaporMassFlux * CONST_RHOFW; + *LatentHeatSub = Ls * (*VaporMassFlux) * CONST_RHOFW; *LatentHeat = 0; *Evap = 0; veg_var->throughfall = 0; @@ -246,7 +246,7 @@ func_canopy_energy_bal(double Tfoliage, root, dryFrac, shortwave, Catm, CanopLayerBnd); *Wdew /= MM_PER_M; - *LatentHeat = Le * *Evap * CONST_RHOFW; + *LatentHeat = Le * (*Evap) * CONST_RHOFW; *LatentHeatSub = 0; } diff --git a/vic/vic_run/src/runoff.c b/vic/vic_run/src/runoff.c index 6308e28b0..a72a988a0 100644 --- a/vic/vic_run/src/runoff.c +++ b/vic/vic_run/src/runoff.c @@ -199,7 +199,7 @@ runoff(cell_data_struct *cell, tmp_liq = resid_moist[lindex]; } - if (liq[lindex] > resid_moist[lindex]) { + if (tmp_liq > resid_moist[lindex]) { Q12[lindex] = calc_Q12(Ksat[lindex], tmp_liq, resid_moist[lindex], soil_con->max_moist[lindex], @@ -490,15 +490,18 @@ compute_runoff_and_asat(soil_con_struct *soil_con, * @brief Calculate drainage between two layers ******************************************************************************/ double -calc_Q12(double Ksat, double init_moist, double resid_moist, - double max_moist, double expt) +calc_Q12(double Ksat, + double init_moist, + double resid_moist, + double max_moist, + double expt) { double Q12; Q12 = init_moist - pow(pow(init_moist - resid_moist, 1.0 - expt) - - Ksat / pow(max_moist - resid_moist, expt) * (1.0 - expt), - 1.0 / (1.0 - expt)) - resid_moist; + Ksat / + pow(max_moist - resid_moist, expt) * (1.0 - expt), + 1.0 / (1.0 - expt)) - resid_moist; return Q12; } - diff --git a/vic/vic_run/src/snow_intercept.c b/vic/vic_run/src/snow_intercept.c index ebc13174b..b541cb4ab 100644 --- a/vic/vic_run/src/snow_intercept.c +++ b/vic/vic_run/src/snow_intercept.c @@ -518,7 +518,7 @@ snow_intercept(double Dt, /* Energy released by freezing of intercepted water is added to the MeltEnergy */ - *MeltEnergy += (CONST_LATICE * *IntRain * CONST_RHOFW) / (Dt); + *MeltEnergy += (CONST_LATICE * (*IntRain) * CONST_RHOFW) / (Dt); *IntRain = 0.0; } diff --git a/vic/vic_run/src/vic_run.c b/vic/vic_run/src/vic_run.c index 98b763655..f885d7514 100644 --- a/vic/vic_run/src/vic_run.c +++ b/vic/vic_run/src/vic_run.c @@ -382,6 +382,11 @@ vic_run(force_data_struct *force, } } + // Compute gridcell-averaged albedo + calc_gridcell_avg_albedo(&all_vars->gridcell_avg.avg_albedo, + force->shortwave[NR], Nveg, overstory, + energy, snow, veg_con, soil_con); + /**************************** Run Lake Model ****************************/