diff --git a/.github.com/CONTRIBUTING.md b/.github/CONTRIBUTING.md
similarity index 100%
rename from .github.com/CONTRIBUTING.md
rename to .github/CONTRIBUTING.md
diff --git a/.github.com/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
similarity index 100%
rename from .github.com/ISSUE_TEMPLATE.md
rename to .github/ISSUE_TEMPLATE.md
diff --git a/.github.com/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
similarity index 100%
rename from .github.com/PULL_REQUEST_TEMPLATE.md
rename to .github/PULL_REQUEST_TEMPLATE.md
diff --git a/ci/requirements.yml b/ci/requirements.yml
index a7caa8514..d13b1ce93 100644
--- a/ci/requirements.yml
+++ b/ci/requirements.yml
@@ -1,4 +1,6 @@
name: vic_test_env
+channels:
+ - conda-forge
dependencies:
- python=3.5
- numpy
diff --git a/docs/Development/ReleaseNotes.md b/docs/Development/ReleaseNotes.md
index fb307ce16..e96ef1c2e 100644
--- a/docs/Development/ReleaseNotes.md
+++ b/docs/Development/ReleaseNotes.md
@@ -13,6 +13,52 @@ To check which release of VIC you are running:
- For VIC 4, type `vicNl -v`
- For VIC 5 and later, type `vic_{classic,image}.exe -v`
+------------------------------
+## VIC 5.0.1
+
+**Release date: (February 1, 2017)**
+
+#### Bug Fixes:
+
+1. Fixed image driver history file name timestamp ([GH#635](https://github.com/UW-Hydro/VIC/pull/635))
+
+ After the fix, the timestamp appeared in the image driver output history filename is the beginning time of the time period in the file.
+
+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).
+
+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))
+
+5. Fixed a bug related to `make_lastday` function ([GH#647](https://github.com/UW-Hydro/VIC/pull/647))
+
+ Before the fix, the input arguments to function `make_lastday` are sometimes in a wrong order. The bug caused error when trying to write state file on a leap day.
+
+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.
+
+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.
+
+8. Fixed a bug related to `run_cell` and `mask` variables in image driver inputs ([GH#662](https://github.com/UW-Hydro/VIC/pull/662))
+
+ Before the fix, active cell was controlled by `mask` variable in the domain file in image driver, and `run_cell` variable in the parameter file was not actually used. Now `run_cell` variable in the parameter file controls active cells (`run_cell` must be within the mask defined by the domain file).
+
+9. Fixed a time precision bug for long simulations ([GH#668](https://github.com/UW-Hydro/VIC/pull/668))
+
+ Before the fix, the timestamps of long VIC runs were incorrect in some cases due to precision issue in timestamp generation. This resulted in incorrect output timestamps after running for a long period of time, or output termination. Please refer to [GH#668](https://github.com/UW-Hydro/VIC/pull/668) for details on this bug fix.
+
+10. Fixed a bug related to forcing and simulation start time ([GH#671](https://github.com/UW-Hydro/VIC/pull/671))
+
+ 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/7766/UW-Hydro/VIC.svg)](https://zenodo.org/badge/latestdoi/7766/UW-Hydro/VIC)
diff --git a/docs/Documentation/Drivers/Classic/ForcingData.md b/docs/Documentation/Drivers/Classic/ForcingData.md
index 504b4a5a5..49106ee14 100644
--- a/docs/Documentation/Drivers/Classic/ForcingData.md
+++ b/docs/Documentation/Drivers/Classic/ForcingData.md
@@ -1,6 +1,6 @@
# VIC Forcings Files
-The VIC Classic Driver requires subdaily forcings (meteorological or other). The required forcing variables vary depending options set in the global parameter file.
+The VIC Classic Driver requires subdaily forcings (meteorological or other). Forcing timestep must be the same as snow model timestep, which is specified by the `SNOW_STEPS_PER_DAY` parameter in the [Global Parameter File](GlobalParam.md). The required forcing variables and units are listed below and must also be specified in the [Global Parameter File](GlobalParam.md)
#### Meteorological Forcings, Required in all simulations:
diff --git a/docs/Documentation/Drivers/Classic/GlobalParam.md b/docs/Documentation/Drivers/Classic/GlobalParam.md
index c7c3c1340..0b434d84f 100644
--- a/docs/Documentation/Drivers/Classic/GlobalParam.md
+++ b/docs/Documentation/Drivers/Classic/GlobalParam.md
@@ -75,8 +75,6 @@ Generally these default values do not need to be overridden.
| BLOWING_SPATIAL_WIND | string | TRUE or FALSE | If TRUE, multiple wind speed ranges, calculated according to a probability distribution, are used to determine the sublimation flux from blowing snow. If FALSE, then a single wind speed is used. See Lu and Pomeroy (1997) for details.
Default: TRUE. |
| COMPUTE_TREELINE | string or integer | FALSE or veg class id | Options for handling above-treeline vegetation:FALSE = Do not compute treeline or replace vegetation above the treeline.CLASS_ID = Compute the treeline elevation based on average July temperatures; for those elevation bands with elevations above the treeline (or the entire grid cell if SNOW_BAND == 1 and the grid cell elevation is above the tree line), if they contain vegetation tiles having overstory, replace that vegetation with the vegetation having id CLASS_ID in the vegetation library. NOTE 1: You MUST supply VIC with a July average air temperature, in the optional July_Tavg field, AND set theJULY_TAVG_SUPPLIED option to TRUE so that VIC can read the soil parameter file correctly. NOTE 2: If LAKES=TRUE, COMPUTE_TREELINE MUST be FALSE.Default = FALSE. |
| CORRPREC | string | TRUE or FALSE | If TRUE correct precipitation for gauge undercatch. NOTE: This option is not supported when using snow/elevation bands. Default = FALSE. |
-| MAX_SNOW_TEMP | float | deg C | Maximum temperature at which snow can fall. Default = 0.5 C. |
-| MIN_RAIN_TEMP | float | deg C | Minimum temperature at which rain can fall. Default = -0.5 C. |
| SPATIAL_SNOW | string | TRUE or FALSE | Option to allow spatial heterogeneity in snow water equivalent (yielding partial snow coverage) when the snow pack is melting:FALSE = Assume snow water equivalent is constant across grid cell.TRUE = Assume snow water equivalent is distributed horizontally with a uniform (linear) distribution, so that some portion of the grid cell has 0 snow pack. This requires specifying the max_snow_distrib_slope value as an extra field in the soil parameter file. NOTE: max_snow_distrib_slope should be set to twice the desired minimum spatial average snow pack depth [m]. I.e., if we define depth_thresh to be the minimum spatial average snow depth below which coverage < 1.0, then max_snow_distrib_slope = 2*depth_thresh. NOTE: Partial snow coverage is only computed when the snow pack has started melting and the spatial average snow pack depth <= max_snow_distrib_slope/2. During the accumulation season, coverage is 1.0. Even after the pack has started melting and depth <= max_snow_distrib_slope/2, new snowfall resets coverage to 1.0, and the previous partial coverage is stored. Coverage remains at 1.0 until the new snow has melted away, at which point the previous partial coverage is recovered. Default = FALSE. |
## Turbulent Flux Parameters
@@ -152,7 +150,7 @@ All FORCING filenames are actually the pathname, and prefix for gridded data typ
| FORCE_ENDIAN | string | BIG or LITTLE | Identifies the architecture of the machine on which the binary forcing files were created:BIG = big-endian (e.g. SUN).LITTLE = little-endian (e.g. PC/linux). Model will identify the endian of the current machine, and swap bytes if necessary. Required for binary forcing file, not used for ASCII forcing file. |
| N_TYPES | int | N/A | Number of columns in the current data file, with the following exception: for the vegetation history variables ALBEDO, LAI_IN, and FCANOPY, there must be multiple columns for these variables, one per vegetation tile. In this case, ALBEDO, LAI_IN, and FCANOPY each count as only 1 variable despite covering multiple columns. |
| FORCE_TYPE | stringstringfloat | VarName(un)signedmultiplier | Defines what forcing types are read from the file, and in what order. For ASCII file only the forcing type needs to be defined, but for Binary file each line must also define whether the column is SIGNED or UNSIGNED short int and by what factor values are multiplied before being written to output. Note: Unlike other variables, ALBEDO, LAI_IN, and FCANOPY, each span multiple columns, one column per veg tile. This will generally vary from one grid cell to the next as the number of veg tiles varies. However, ALBEDO, LAI_IN, and FCANOPY should each have only one FORCE_TYPE entry. [Click here for details](ForcingData.md). |
-| FORCE_STEPS_PER_DAY | integer | steps | Number of timesteps per day in forcing file (must be >= 1) |
+| FORCE_STEPS_PER_DAY | integer | steps | Number of timesteps per day in forcing file (must be = SNOW_STPES_PER_DAY) |
| FORCEYEAR | integer | year | Year meteorological forcing files start |
| FORCEMONTH | integer | month | Month meteorological forcing files start |
| FORCEDAY | integer | day | Day meteorological forcing files start |
diff --git a/docs/Documentation/Drivers/Classic/RunVIC.md b/docs/Documentation/Drivers/Classic/RunVIC.md
index da78dfb3c..1dd4ed4e0 100644
--- a/docs/Documentation/Drivers/Classic/RunVIC.md
+++ b/docs/Documentation/Drivers/Classic/RunVIC.md
@@ -9,7 +9,7 @@
- Clang (`clang` version 3+)
VIC has also been compiled using these compilers:
-
+
- Intel (`icc`)
- PGI (`pgcc`)
@@ -28,7 +28,7 @@
At the command prompt, type:
- vic_classic.exe -g global_parameter_filename
+ ./vic_classic.exe -g global_parameter_filename
where `global_parameter_filename` = name of the global parameter file corresponding to your project.
diff --git a/docs/Documentation/Drivers/Image/Domain.md b/docs/Documentation/Drivers/Image/Domain.md
new file mode 100644
index 000000000..cdfedb738
--- /dev/null
+++ b/docs/Documentation/Drivers/Image/Domain.md
@@ -0,0 +1,51 @@
+# VIC Domain file
+
+The Image Driver uses the [NetCDF](http://www.unidata.ucar.edu/software/netcdf/) file format to define model running domain.
+
+Below is a list of variables in the domain netCDF file. The dimensions of the netCDF file are `lat` and `lon`. Note that here only the type of variables (i.e., MASK, AREA, FRAC, LAT and LON) is listed; corresponding variable names in the input netCDF file are specified by user in the [Global Parameter File](GlobalParam.md). All the listed variables are required.
+
+| Variable | Dimension | Units | Type | Description |
+|------------|-------------|----------|--------|-------------|
+| LAT | [lat] | degree | double | Latitudes |
+| LON | [lon] | degree | double | Longitues |
+| MASK | [lat, lon] | N/A | integer | Mask of domain. 1 for grid cells inside considered domain; 0 for grid cells outside of domain. Cells outside of domain will not be run. Use run_cell variable in the parameter file to turn on/off active cells inside domain. |
+| AREA | [lat, lon] | m2 | double | Area of grid cells. |
+| FRAC | [lat, lon] | N/A | double | Fraction of grid cells that is land. |
+
+# Example netCDF format VIC 5 image driver domain file
+
+```shell
+ncdump -h /ArkRed.domain.nc
+netcdf ArkRed.domain {
+dimensions:
+ lat = 66 ;
+ lon = 125 ;
+variables:
+ int mask(lat, lon) ;
+ mask:comment = "0 indicates grid cell outside of domain" ;
+ mask:long_name = "domain mask" ;
+ double lon(lon) ;
+ lon:long_name = "longitude coordinate" ;
+ lon:units = "degrees_east" ;
+ double lat(lat) ;
+ lat:long_name = "latitude coordinate" ;
+ lat:units = "degrees_north" ;
+ double frac(lat, lon) ;
+ frac:long_name = "fraction of grid cell that is active" ;
+ frac:units = "1" ;
+ double area(lat, lon) ;
+ area:standard_name = "area" ;
+ area:long_name = "area of grid cell" ;
+ area:units = "m2" ;
+
+// global attributes:
+ :title = "VIC domain data" ;
+ :Conventions = "CF-1.6" ;
+ :history = "Wed Oct 12 15:48:42 2016: ncap2 -s mask=int(mask) ArkRed.domain.nc.float_mask ArkRed.domain.nc\n",
+ "created by ymao, 2016-09-23 18:17:58.761256" ;
+ :user_comment = "VIC domain data" ;
+ :source = "generated from VIC CONUS 1.8 deg model parameters, see Maurer et al. (2002) for more information" ;
+ :nco_openmp_thread_number = 1 ;
+}
+```
+
diff --git a/docs/Documentation/Drivers/Image/ForcingData.md b/docs/Documentation/Drivers/Image/ForcingData.md
index fa3ba1f76..4187dedb7 100644
--- a/docs/Documentation/Drivers/Image/ForcingData.md
+++ b/docs/Documentation/Drivers/Image/ForcingData.md
@@ -1,6 +1,6 @@
# VIC Forcing File
-The VIC Image Driver requires a NetCDF file with gridded subdaily forcings. The required forcing variables and units are listed below and must also be specified in the [Global Parameter File](GlobalParam.md):
+The VIC Image Driver requires a NetCDF file with gridded subdaily forcings. Forcing timestep must be the same as snow model timestep, which is specified by the `SNOW_STEPS_PER_DAY` parameter in the [Global Parameter File](GlobalParam.md). The required forcing variables and units are listed below and must also be specified in the [Global Parameter File](GlobalParam.md):
#### Meteorological Forcings, Required in all simulations:
@@ -38,11 +38,6 @@ variables:
lat:long_name = "latitude of grid cell center" ;
lat:units = "degrees_north" ;
lat:axis = "Y" ;
- double mask(lat, lon) ;
- mask:_FillValue = 0. ;
- mask:comment = "0 value indicates cell is not active" ;
- mask:long_name = "fraction of grid cell that is activedomain mask" ;
- mask:note = "unitlessunitless" ;
float prcp(time, lat, lon) ;
prcp:_FillValue = 9.96921e+36f ;
prcp:long_name = "PREC" ;
diff --git a/docs/Documentation/Drivers/Image/GlobalParam.md b/docs/Documentation/Drivers/Image/GlobalParam.md
index 677d71263..de2fa16d7 100644
--- a/docs/Documentation/Drivers/Image/GlobalParam.md
+++ b/docs/Documentation/Drivers/Image/GlobalParam.md
@@ -157,7 +157,7 @@ See the [example file](#example-global-parameter-file) at the end of this page f
# Define Domain file
-The folloiwng options describe the input domain file information.
+The folloiwng options describe the input domain file information. See [Domain File](Domain.md) for details about the domain file.
| Name | Type | Units | Description |
|-------------|---------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------|
diff --git a/docs/Documentation/Drivers/Image/Inputs.md b/docs/Documentation/Drivers/Image/Inputs.md
index dff766816..2c69779c8 100644
--- a/docs/Documentation/Drivers/Image/Inputs.md
+++ b/docs/Documentation/Drivers/Image/Inputs.md
@@ -7,6 +7,7 @@ To run VIC, several sets of input data are necessary:
* [Global Parameter File](GlobalParam.md): This is the main input file for VIC. It points VIC to the locations of the other input/output files and sets parameters that govern the simulation (e.g., start/end dates, modes of operation).
* [Meteorological Forcing Files](ForcingData.md): Gridded, sub-daily timeseries of meteorological variables as inputs.
* [Parameters File](Params.md): Spatially distributed parameters describing the land surface.
+* [Domain File](Domain.md): Domain information of VIC run.
And a few more are optional:
diff --git a/docs/Documentation/Drivers/Image/Params.md b/docs/Documentation/Drivers/Image/Params.md
index bb05c324c..243904ba2 100644
--- a/docs/Documentation/Drivers/Image/Params.md
+++ b/docs/Documentation/Drivers/Image/Params.md
@@ -16,7 +16,7 @@ Below is a list of soil parameters.
| Variable Name | Dimension | Units | Type | Number of Values | Description |
|--------------------------|--------------------|----------|--------|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| run_cell | [lat, lon] | N/A | int | 1 | 1 = Run Grid Cell, 0 = Do Not Run |
+| run_cell | [lat, lon] | N/A | int | 1 | 1 = Run Grid Cell, 0 = Do Not Run. Must be zero for all grid cells outside of the mask defined in the domain netCDF file. |
| gridcel | [lat, lon] | N/A | int | 1 | Grid cell number |
| lat | [lat, lon] | degrees | double | 1 | Latitude of grid cell |
| lon | [lat, lon] | degrees | double | 1 | Longitude of grid cell |
@@ -173,13 +173,6 @@ variables:
double lon(lon) ;
lon:units = "degrees_east" ;
lon:long_name = "longitude of grid cell center" ;
- int mask(lat, lon) ;
- mask:long_name = "area of grid cell" ;
- mask:comment = "0 value indicates cell is not active" ;
- mask:note = "unitless" ;
- mask:standard_name = "area" ;
- mask:units = "m2" ;
- mask:axis = "Y" ;
int layer(nlayer) ;
layer:long_name = "soil layer" ;
int run_cell(lat, lon) ;
diff --git a/docs/Documentation/Drivers/Image/RunVIC.md b/docs/Documentation/Drivers/Image/RunVIC.md
index 078e0527a..a8847ee4a 100644
--- a/docs/Documentation/Drivers/Image/RunVIC.md
+++ b/docs/Documentation/Drivers/Image/RunVIC.md
@@ -44,13 +44,13 @@ In some versions of the MPI library (e.g. OPEN-MPI with Intel), you may also nee
At the command prompt, type:
-`vic_image.exe -g global_parameter_filename.txt`
+ ./vic_image.exe -g global_parameter_filename.txt
where `global_parameter_filename` = name of the global parameter file corresponding to your project.
To run VIC image driver using multiple processors, type the following instead:
-`mpiexec -np n_proc vic_image.exe -g global_parameter_filename.txt`
+ mpiexec -np $n_proc ./vic_image.exe -g global_parameter_filename.txt
where `n_proc` = number of processors to be used
@@ -58,6 +58,6 @@ where `n_proc` = number of processors to be used
VIC has a few other command line options:
-- `vic_image.exe -v`: says which version of VIC this is
-- `vic_image.exe -h`: prints a list of all the VIC command-line options
-- `vic_image.exe -o`: prints a list of all of the current compile-time settings in this executable; to change these settings, you must edit the appropriate header files (e.g. `vic_def.h` or `vic_driver_shared.h`) and recompile using `make full`.
+- `./vic_image.exe -v`: says which version of VIC this is
+- `./vic_image.exe -h`: prints a list of all the VIC command-line options
+- `./vic_image.exe -o`: prints a list of all of the current compile-time settings in this executable; to change these settings, you must edit the appropriate header files (e.g. `vic_def.h` or `vic_driver_shared.h`) and recompile using `make full`.
diff --git a/docs/Documentation/Drivers/Image/StateFile.md b/docs/Documentation/Drivers/Image/StateFile.md
index ba6d43179..17447e6bf 100644
--- a/docs/Documentation/Drivers/Image/StateFile.md
+++ b/docs/Documentation/Drivers/Image/StateFile.md
@@ -38,8 +38,8 @@ The following variables define the basic model information, including grid cell
| snow_band | snow_band | int | Snow band indices |
| layer | nlayer | int | Soil layer indices |
| frost_area | frost_area | int | Frost area indices |
-| dz_node | soil_node | double | Distances between soil thermal nodes [m] |
-| node_depth | soil_node | double | Depth from surface of each soil thermal node (first node should have a depth of 0m indicating it is at the surface) [m] |
+| dz_node | [soil_node, lat, lon] | double | Distances between soil thermal nodes [m] |
+| node_depth | [soil_node, lat, lon] | double | Depth from surface of each soil thermal node (first node should have a depth of 0m indicating it is at the surface) [m] |
* * *
diff --git a/docs/Documentation/References.md b/docs/Documentation/References.md
index 9352afb2a..d8f336c35 100644
--- a/docs/Documentation/References.md
+++ b/docs/Documentation/References.md
@@ -2,7 +2,7 @@
## Primary Historical Reference
-Liang, X., D. P. Lettenmaier, E. F. Wood, and S. J. Burges, 1994: A Simple hydrologically Based Model of Land Surface Water and Energy Fluxes for GSMs, _J. Geophys. Res._, **99**(D7), 14415-14428, [doi:10.1029/94JD00483](http://dx.doi.org/10.1029/94JD00483).
+Liang, X., D. P. Lettenmaier, E. F. Wood, and S. J. Burges (1994), A simple hydrologically based model of land surface water and energy fluxes for general circulation models, _J. Geophys. Res._, **99**(D7), 14415–14428, [doi:10.1029/94JD00483](http://dx.doi.org/10.1029/94JD00483).
### Other Historical References
diff --git a/mkdocs.yml b/mkdocs.yml
index 1c9107ef7..c989432a5 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -64,6 +64,7 @@ pages:
- 'Inputs': 'Documentation/Drivers/Image/Inputs.md'
- 'Outputs': 'Documentation/Drivers/Image/Outputs.md'
- 'Params': 'Documentation/Drivers/Image/Params.md'
+ - 'Domain': 'Documentation/Drivers/Image/Domain.md'
- 'RunVIC': 'Documentation/Drivers/Image/RunVIC.md'
- 'Lake Param': 'Documentation/Drivers/Image/LakeParam.md'
- 'StateFile': 'Documentation/Drivers/Image/StateFile.md'
diff --git a/tests/system/system_tests.cfg b/tests/system/system_tests.cfg
index a03d8a7c7..0d2f5c7fb 100644
--- a/tests/system/system_tests.cfg
+++ b/tests/system/system_tests.cfg
@@ -144,6 +144,7 @@ STATE_FORMAT=BINARY
test_description = Exact restart (falseFULL_ENERGY flaseFROZEN_SOIL) - image driver
driver = image
global_parameter_file = global.image.STEHE.restart.txt
+mpi_proc = 4
expected_retval = 0
check = exact_restart
[[restart]]
@@ -158,6 +159,7 @@ FROZEN_SOIL=FALSE
test_description = Exact restart (trueFULL_ENERGY flaseFROZEN_SOIL) - image driver
driver = image
global_parameter_file = global.image.STEHE.restart.txt
+mpi_proc = 4
expected_retval = 0
check = exact_restart
[[restart]]
@@ -172,6 +174,7 @@ FROZEN_SOIL=FALSE
test_description = Exact restart (falseFULL_ENERGY trueFROZEN_SOIL) - image driver
driver = image
global_parameter_file = global.image.STEHE.restart.FROZEN_SOIL.txt
+mpi_proc = 4
expected_retval = 0
check = exact_restart
[[restart]]
@@ -187,6 +190,7 @@ NODES=10
test_description = Exact restart (trueFULL_ENERGY trueFROZEN_SOIL) - image driver
driver = image
global_parameter_file = global.image.STEHE.restart.FROZEN_SOIL.txt
+mpi_proc = 4
expected_retval = 0
check = exact_restart
[[restart]]
diff --git a/vic/drivers/classic/src/get_global_param.c b/vic/drivers/classic/src/get_global_param.c
index 587adbc04..4a6534ab9 100644
--- a/vic/drivers/classic/src/get_global_param.c
+++ b/vic/drivers/classic/src/get_global_param.c
@@ -671,6 +671,16 @@ get_global_param(FILE *gp)
log_err("SKIPYEAR has been deprecated. To avoid writing output"
"to history files, set AGGFREQ == FREQ_NEVER");
}
+ else if (strcasecmp("MAX_SNOW_TEMP", optstr) == 0) {
+ log_err("MAX_SNOW_TEMP has been deprecated. To"
+ "specify a maximum snow temperature, use the option"
+ "SNOW_MAX_SNOW_TEMP in the vic constants file.")
+ }
+ else if (strcasecmp("MIN_RAIN_TEMP", optstr) == 0) {
+ log_err("MIN_RAIN_TEMP has been deprecated. To"
+ "specify a minimum rain temperature, use the option"
+ "SNOW_MIN_RAIN_TEMP in the vic constants file.")
+ }
/***********************************
Unrecognized Global Parameter Flag
@@ -891,7 +901,7 @@ get_global_param(FILE *gp)
// Validate simulation end date and/or number of timesteps
- make_lastday(global_param.endyear, global_param.calendar, lastday);
+ make_lastday(global_param.calendar, global_param.endyear, lastday);
if (global_param.nrecs == 0 && global_param.endyear == 0 &&
global_param.endmonth == 0 && global_param.endday == 0) {
@@ -1204,7 +1214,7 @@ get_global_param(FILE *gp)
global_param.statesec);
}
// Check for month, day in range
- make_lastday(global_param.stateyear, global_param.calendar,
+ make_lastday(global_param.calendar, global_param.stateyear,
lastday);
if (global_param.stateday > lastday[global_param.statemonth - 1] ||
global_param.statemonth < 1 ||
diff --git a/vic/drivers/image/src/get_global_param.c b/vic/drivers/image/src/get_global_param.c
index c1865f1d0..3e8dc38f0 100644
--- a/vic/drivers/image/src/get_global_param.c
+++ b/vic/drivers/image/src/get_global_param.c
@@ -727,7 +727,7 @@ get_global_param(FILE *gp)
}
// Validate simulation end date and/or number of timesteps
- make_lastday(global_param.endyear, global_param.calendar, lastday);
+ make_lastday(global_param.calendar, global_param.endyear, lastday);
if (global_param.nrecs == 0 && global_param.endyear == 0 &&
global_param.endmonth == 0 && global_param.endday == 0) {
@@ -895,7 +895,7 @@ get_global_param(FILE *gp)
global_param.statesec);
}
// Check for month, day in range
- make_lastday(global_param.stateyear, global_param.calendar,
+ make_lastday(global_param.calendar, global_param.stateyear,
lastday);
if (global_param.stateday > lastday[global_param.statemonth - 1] ||
global_param.statemonth < 1 ||
diff --git a/vic/drivers/image/src/vic_force.c b/vic/drivers/image/src/vic_force.c
index 68a30f421..11caca455 100644
--- a/vic/drivers/image/src/vic_force.c
+++ b/vic/drivers/image/src/vic_force.c
@@ -72,8 +72,10 @@ vic_force(void)
// global_param.forceoffset[0] resets every year since the met file restarts
// every year
+ // global_param.forceskip[0] should also reset to 0 after the first year
if (current > 1 && (dmy[current].year != dmy[current - 1].year)) {
global_param.forceoffset[0] = 0;
+ global_param.forceskip[0] = 0;
}
// only the time slice changes for the met file reads. The rest is constant
@@ -517,10 +519,11 @@ get_forcing_file_info(param_set_struct *param_set,
// check that this forcing file will work
if (param_set->force_steps_per_day[file_num] !=
- global_param.model_steps_per_day) {
- log_err("Forcing file timestep must match the model timestep. "
- "Model timesteps per day is set to %zu and the forcing file "
- "timestep is set to %zu", global_param.model_steps_per_day,
+ global_param.snow_steps_per_day) {
+ log_err("Forcing file timestep must match the snow model timestep. "
+ "Snow model timesteps per day is set to %zu and the forcing "
+ "file timestep is set to %zu",
+ global_param.snow_steps_per_day,
param_set->force_steps_per_day[file_num])
}
if (calendar != global_param.calendar) {
diff --git a/vic/drivers/python/setup.py b/vic/drivers/python/setup.py
index 44a58530d..68e00de93 100644
--- a/vic/drivers/python/setup.py
+++ b/vic/drivers/python/setup.py
@@ -25,7 +25,7 @@
MAJOR = 5
MINOR = 0
-MICRO = 0
+MICRO = 1
ISRELEASED = True
VERSION = '%d.%d.%d' % (MAJOR, MINOR, MICRO)
QUALIFIER = ''
diff --git a/vic/drivers/shared_all/include/vic_version.h b/vic/drivers/shared_all/include/vic_version.h
index e9b76fabf..f3062b87c 100644
--- a/vic/drivers/shared_all/include/vic_version.h
+++ b/vic/drivers/shared_all/include/vic_version.h
@@ -31,11 +31,11 @@
#define STR(x) STR_HELPER(x)
#ifndef VERSION
-#define VERSION "5.0.0 September 2, 2016"
+#define VERSION "5.0.1 February 1, 2017"
#endif
#ifndef SHORT_VERSION
-#define SHORT_VERSION "5.0.0"
+#define SHORT_VERSION "5.0.1"
#endif
#ifndef GIT_VERSION
diff --git a/vic/drivers/shared_all/src/make_dmy.c b/vic/drivers/shared_all/src/make_dmy.c
index 9abbdcb02..1b48cbdf0 100644
--- a/vic/drivers/shared_all/src/make_dmy.c
+++ b/vic/drivers/shared_all/src/make_dmy.c
@@ -43,8 +43,6 @@ make_dmy(global_param_struct *global)
double dt_time_units, start_num, end_num, force_num,
numdate;
- dt_seconds_to_time_units(global->time_units, global->dt, &dt_time_units);
-
start_dmy.dayseconds = global->startsec;
start_dmy.year = global->startyear;
start_dmy.day = global->startday;
@@ -98,8 +96,8 @@ make_dmy(global_param_struct *global)
global->calendar, global->time_units);
global->forceskip[i] =
- (unsigned int) ((start_num - force_num) *
- (double) param_set.force_steps_per_day[i]);
+ (unsigned int) round((start_num - force_num) *
+ (double) param_set.force_steps_per_day[i]);
}
}
@@ -107,9 +105,10 @@ make_dmy(global_param_struct *global)
temp = calloc(global->nrecs, sizeof(*temp));
/** Create Date Structure for each Model Time Step **/
- for (i = 0, numdate = start_num;
- i < global->nrecs;
- i++, numdate += dt_time_units) {
+ for (i = 0; i < global->nrecs; i++) {
+ dt_seconds_to_time_units(global->time_units, i * global->dt,
+ &dt_time_units);
+ numdate = start_num + dt_time_units;
num2date(global->time_origin_num, numdate, 0., global->calendar,
global->time_units, &temp[i]);
}
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 8257b1249..98542935a 100644
--- a/vic/drivers/shared_image/include/vic_driver_shared_image.h
+++ b/vic/drivers/shared_image/include/vic_driver_shared_image.h
@@ -196,11 +196,14 @@ void compare_ncdomain_with_global_domain(char *ncfile);
void free_force(force_data_struct *force);
void free_veg_hist(veg_hist_struct *veg_hist);
void get_domain_type(char *cmdstr);
-size_t get_global_domain(char *fname, domain_struct *global_domain,
- bool coords_only);
+size_t get_global_domain(char *domain_nc_name, char *param_nc_name,
+ domain_struct *global_domain);
+void copy_domain_info(domain_struct *domain_from, domain_struct *domain_to);
+void get_nc_latlon(char *nc_name, domain_struct *nc_domain);
size_t get_nc_dimension(char *nc_name, char *dim_name);
void get_nc_var_attr(char *nc_name, char *var_name, char *attr_name,
char **attr);
+int get_nc_var_type(char *nc_name, char *var_name);
int get_nc_varndimensions(char *nc_name, char *var_name);
int get_nc_field_double(char *nc_name, char *var_name, size_t *start,
size_t *count, double *var);
diff --git a/vic/drivers/shared_image/src/check_domain_info.c b/vic/drivers/shared_image/src/check_domain_info.c
index 1095b05a9..d67e9bc90 100644
--- a/vic/drivers/shared_image/src/check_domain_info.c
+++ b/vic/drivers/shared_image/src/check_domain_info.c
@@ -28,8 +28,8 @@
#include
/******************************************************************************
- * @brief Check that the cooridnates, dimensions, and mask variables in a
- netcdf file matches the global domain.
+ * @brief Check that the cooridnates and dimensions in a netcdf file matches
+ the global domain.
*****************************************************************************/
void
compare_ncdomain_with_global_domain(char *ncfile)
@@ -40,10 +40,14 @@ compare_ncdomain_with_global_domain(char *ncfile)
size_t i;
- ncfile_domain.info = global_domain.info;
-
- // read the domain info from ncfile (e.g. parameters file or state file)
- get_global_domain(ncfile, &ncfile_domain, true);
+ // read the lat lon coordinates info from ncfile
+ // (e.g. parameters file or state file)
+ ncfile_domain.locations =
+ malloc(global_domain.ncells_total *
+ sizeof(*(ncfile_domain.locations)));
+ check_alloc_status(ncfile_domain.locations, "Memory allocation error.");
+ copy_domain_info(&global_domain, &ncfile_domain);
+ get_nc_latlon(ncfile, &ncfile_domain);
// using the ncfile_domain, we can compare the values to the global domain.
@@ -57,11 +61,6 @@ compare_ncdomain_with_global_domain(char *ncfile)
// loop over all grid cells and check that the two domains are identical
for (i = 0; i < global_domain.ncells_total; i++) {
- // mask matches
- if (ncfile_domain.locations[i].run < global_domain.locations[i].run) {
- log_err("parameter file mask for gridcell %zu is zero and the "
- "domain file specifies that this cell should be run", i);
- }
// latitude matches
if (!assert_close_double(ncfile_domain.locations[i].latitude,
global_domain.locations[i].latitude,
diff --git a/vic/drivers/shared_image/src/get_global_domain.c b/vic/drivers/shared_image/src/get_global_domain.c
index 6dbdd0574..07e6a243c 100644
--- a/vic/drivers/shared_image/src/get_global_domain.c
+++ b/vic/drivers/shared_image/src/get_global_domain.c
@@ -30,23 +30,23 @@
* @brief Get global domain information.
*****************************************************************************/
size_t
-get_global_domain(char *nc_name,
- domain_struct *global_domain,
- bool coords_only)
+get_global_domain(char *domain_nc_name,
+ char *param_nc_name,
+ domain_struct *global_domain)
{
int *run = NULL;
+ int *mask = NULL;
+ int typeid;
double *var = NULL;
- double *var_lon = NULL;
- double *var_lat = NULL;
size_t i;
size_t j;
size_t d2count[2];
size_t d2start[2];
- size_t d1count[1];
- size_t d1start[1];
- global_domain->n_nx = get_nc_dimension(nc_name, global_domain->info.x_dim);
- global_domain->n_ny = get_nc_dimension(nc_name, global_domain->info.y_dim);
+ global_domain->n_nx = get_nc_dimension(domain_nc_name,
+ global_domain->info.x_dim);
+ global_domain->n_ny = get_nc_dimension(domain_nc_name,
+ global_domain->info.y_dim);
d2start[0] = 0;
d2start[1] = 0;
@@ -56,19 +56,45 @@ get_global_domain(char *nc_name,
// get total number of gridcells in domain
global_domain->ncells_total = global_domain->n_ny * global_domain->n_nx;
- // allocate memory for cells to be run
+ // allocate memory for mask and cells to be run
+ mask = malloc(global_domain->ncells_total * sizeof(*mask));
+ check_alloc_status(mask, "Memory allocation error.");
run = malloc(global_domain->ncells_total * sizeof(*run));
check_alloc_status(run, "Memory allocation error.");
- get_nc_field_int(nc_name, global_domain->info.mask_var, d2start, d2count,
+ // Get mask variable from the domain file
+ // (check whether mask variable is int type)
+ typeid = get_nc_var_type(domain_nc_name, global_domain->info.mask_var);
+ if (typeid != NC_INT) {
+ log_err("Mask variable in the domain file must be integer type.");
+ }
+ get_nc_field_int(domain_nc_name, global_domain->info.mask_var, d2start, d2count,
+ mask);
+
+ // Get run_cell variable from the parameter file
+ // (check whether run_cell variable is int type)
+ typeid = get_nc_var_type(param_nc_name, "run_cell");
+ if (typeid != NC_INT) {
+ log_err("Run_cell variable in the parameter file must be integer type.");
+ }
+ get_nc_field_int(param_nc_name, "run_cell", d2start, d2count,
run);
+ // Check whether cells with run_cell == 1 are all within the mask domain
+ for (i = 0; i < global_domain->ncells_total; i++) {
+ if (run[i] == 1 && mask[i] != 1) {
+ log_err("Run_cell = 1 should only appear within the mask of the "
+ "domain file.");
+ }
+ }
+
+ // Store active cell information into variables
for (i = 0; i < global_domain->ncells_total; i++) {
if (run[i] == 1) {
global_domain->ncells_active++;
}
}
- debug("%zu active grid cells found in domain mask",
+ debug("%zu active grid cells found in run_cell in the parameter file.",
global_domain->ncells_active);
global_domain->locations =
@@ -78,10 +104,6 @@ get_global_domain(char *nc_name,
initialize_location(&(global_domain->locations[i]));
}
- // allocate memory for variables
- var = malloc(global_domain->ncells_total * sizeof(*var));
- check_alloc_status(var, "Memory allocation error.");
-
for (i = 0; i < global_domain->ncells_total; i++) {
if (run[i] == 1) {
global_domain->locations[i].run = true;
@@ -96,109 +118,173 @@ get_global_domain(char *nc_name,
}
}
+ // allocate memory for variables
+ var = malloc(global_domain->ncells_total * sizeof(*var));
+ check_alloc_status(var, "Memory allocation error.");
+
+ // get area
+ // TBD: read var id from file
+ get_nc_field_double(domain_nc_name, global_domain->info.area_var,
+ d2start, d2count, var);
+ for (i = 0; i < global_domain->ncells_total; i++) {
+ global_domain->locations[i].area = var[i];
+ }
+
+ // get fraction
+ // TBD: read var id from file
+ get_nc_field_double(domain_nc_name, global_domain->info.frac_var,
+ d2start, d2count, var);
+ for (i = 0; i < global_domain->ncells_total; i++) {
+ global_domain->locations[i].frac = var[i];
+ }
+
+ // get lat and lon coordinates
+ get_nc_latlon(domain_nc_name, global_domain);
+
+ // check whether lat and lon coordinates in the parameter file match those
+ // in the domain file
+ compare_ncdomain_with_global_domain(param_nc_name);
+
+ // free memory
+ free(var);
+ free(run);
+
+ return global_domain->ncells_active;
+}
+
+
+/******************************************************************************
+ * @brief Get lat and lon coordinates information from a netCDF file and
+ store in nc_domain structure
+ *****************************************************************************/
+void
+get_nc_latlon(char *nc_name,
+ domain_struct *nc_domain)
+{
+ double *var = NULL;
+ double *var_lon = NULL;
+ double *var_lat = NULL;
+ size_t i;
+ size_t j;
+ size_t d2count[2];
+ size_t d2start[2];
+ size_t d1count[1];
+ size_t d1start[1];
+
+
+ nc_domain->n_nx = get_nc_dimension(nc_name,
+ nc_domain->info.x_dim);
+ nc_domain->n_ny = get_nc_dimension(nc_name,
+ nc_domain->info.y_dim);
+
// Get number of lat/lon dimensions.
- global_domain->info.n_coord_dims = get_nc_varndimensions(nc_name,
- global_domain->info.lon_var);
- if (global_domain->info.n_coord_dims !=
- (size_t) get_nc_varndimensions(nc_name, global_domain->info.lat_var)) {
+ nc_domain->info.n_coord_dims = get_nc_varndimensions(nc_name,
+ nc_domain->info.lon_var);
+ if (nc_domain->info.n_coord_dims !=
+ (size_t) get_nc_varndimensions(nc_name, nc_domain->info.lat_var)) {
log_err("Un even number of dimensions for %s and %s in: %s",
- global_domain->info.lon_var, global_domain->info.lat_var,
+ nc_domain->info.lon_var, nc_domain->info.lat_var,
nc_name);
}
- if (global_domain->info.n_coord_dims == 1) {
+ if (nc_domain->info.n_coord_dims == 1) {
// allocate memory for variables
- var_lon = malloc(global_domain->n_nx * sizeof(*var_lon));
+ var_lon = malloc(nc_domain->n_nx * sizeof(*var_lon));
check_alloc_status(var_lon, "Memory allocation error.");
- var_lat = malloc(global_domain->n_ny * sizeof(*var_lat));
+ var_lat = malloc(nc_domain->n_ny * sizeof(*var_lat));
check_alloc_status(var_lat, "Memory allocation error.");
d1start[0] = 0;
- d1count[0] = global_domain->n_nx;
+ d1count[0] = nc_domain->n_nx;
// get longitude for unmasked grid
- get_nc_field_double(nc_name, global_domain->info.lon_var,
+ get_nc_field_double(nc_name, nc_domain->info.lon_var,
d1start, d1count, var_lon);
- for (j = 0; j < global_domain->n_ny; j++) {
- for (i = 0; i < global_domain->n_nx; i++) {
+ for (j = 0; j < nc_domain->n_ny; j++) {
+ for (i = 0; i < nc_domain->n_nx; i++) {
// rescale to [-180., 180]. Note that the if statement is not strictly
// needed, but it prevents -180 from turning into 180 and vice versa
if (var_lon[i] < -180.f || var_lon[i] > 180.f) {
var_lon[i] -= round(var_lon[i] / 360.f) * 360.f;
}
- global_domain->locations[j * global_domain->n_nx +
- i].longitude = (double) var_lon[i];
+ nc_domain->locations[j * nc_domain->n_nx + i].longitude =
+ (double) var_lon[i];
}
}
d1start[0] = 0;
- d1count[0] = global_domain->n_ny;
+ d1count[0] = nc_domain->n_ny;
// get latitude for unmasked grid
- get_nc_field_double(nc_name, global_domain->info.lat_var,
+ get_nc_field_double(nc_name, nc_domain->info.lat_var,
d1start, d1count, var_lat);
- for (i = 0; i < global_domain->n_ny; i++) {
- for (j = 0; j < global_domain->n_nx; j++) {
- global_domain->locations[i *
- global_domain->n_nx + j].latitude =
+ for (i = 0; i < nc_domain->n_ny; i++) {
+ for (j = 0; j < nc_domain->n_nx; j++) {
+ nc_domain->locations[i * nc_domain->n_nx + j].latitude =
(double) var_lat[i];
}
}
+ // free memory
free(var_lon);
free(var_lat);
}
- else if (global_domain->info.n_coord_dims == 2) {
+ else if (nc_domain->info.n_coord_dims == 2) {
+ // allocate memory for variables
+ var = malloc(nc_domain->ncells_total * sizeof(*var));
+ check_alloc_status(var, "Memory allocation error.");
+
+
+ d2start[0] = 0;
+ d2start[1] = 0;
+ d2count[0] = nc_domain->n_ny;
+ d2count[1] = nc_domain->n_nx;
+
// get longitude for unmasked grid
- get_nc_field_double(nc_name, global_domain->info.lon_var,
+ get_nc_field_double(nc_name, nc_domain->info.lon_var,
d2start, d2count, var);
- for (i = 0; i < global_domain->ncells_total; i++) {
+ for (i = 0; i < nc_domain->ncells_total; i++) {
// rescale to [-180., 180]. Note that the if statement is not strictly
// needed, but it prevents -180 from turning into 180 and vice versa
if (var[i] < -180.f || var[i] > 180.f) {
var[i] -= round(var[i] / 360.f) * 360.f;
}
- global_domain->locations[i].longitude = var[i];
+ nc_domain->locations[i].longitude = var[i];
}
// get latitude for unmasked grid
- get_nc_field_double(nc_name, global_domain->info.lat_var,
+ get_nc_field_double(nc_name, nc_domain->info.lat_var,
d2start, d2count, var);
- for (i = 0; i < global_domain->ncells_total; i++) {
- global_domain->locations[i].latitude = var[i];
+ for (i = 0; i < nc_domain->ncells_total; i++) {
+ nc_domain->locations[i].latitude = var[i];
}
+ // free memory
+ free(var);
}
else {
log_err("Number of dimensions for %s and %s should be 1 or 2 in: %s",
- global_domain->info.lon_var, global_domain->info.lat_var,
+ nc_domain->info.lon_var, nc_domain->info.lat_var,
nc_name);
}
+}
- if (!coords_only) {
- // get area
- // TBD: read var id from file
- get_nc_field_double(nc_name, global_domain->info.area_var,
- d2start, d2count, var);
- for (i = 0; i < global_domain->ncells_total; i++) {
- global_domain->locations[i].area = var[i];
- }
-
- // get fraction
- // TBD: read var id from file
- get_nc_field_double(nc_name, global_domain->info.frac_var,
- d2start, d2count, var);
- for (i = 0; i < global_domain->ncells_total; i++) {
- global_domain->locations[i].frac = var[i];
- }
- }
+/******************************************************************************
+ * @brief Copy domain info from one domain structure to another
+ *****************************************************************************/
+void
+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);
+ strcpy(domain_to->info.lon_var, domain_from->info.lon_var);
+ strcpy(domain_to->info.lat_var, domain_from->info.lat_var);
- // free memory
- free(var);
- free(run);
+ domain_to->n_nx = domain_from->n_nx;
+ domain_to->n_ny = domain_from->n_ny;
- return global_domain->ncells_active;
+ domain_to->ncells_total = domain_from->ncells_total;
}
/******************************************************************************
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 418f56277..6a91c8ebc 100644
--- a/vic/drivers/shared_image/src/get_nc_var_attr.c
+++ b/vic/drivers/shared_image/src/get_nc_var_attr.c
@@ -27,7 +27,7 @@
#include
/******************************************************************************
- * @brief Get netCDF dimension.
+ * @brief Get netCDF variable attributes.
*****************************************************************************/
void
get_nc_var_attr(char *nc_name,
diff --git a/vic/drivers/shared_image/src/get_nc_var_type.c b/vic/drivers/shared_image/src/get_nc_var_type.c
new file mode 100644
index 000000000..80a674de6
--- /dev/null
+++ b/vic/drivers/shared_image/src/get_nc_var_type.c
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * @section DESCRIPTION
+ *
+ * Get netCDF variable type.
+ *
+ * @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 Get netCDF variable type.
+ *****************************************************************************/
+int
+get_nc_var_type(char *nc_name,
+ char *var_name)
+{
+ int nc_id;
+ int var_id;
+ int status;
+ int xtypep;
+
+ // open the netcdf file
+ status = nc_open(nc_name, NC_NOWRITE, &nc_id);
+ check_nc_status(status, "Error opening %s", nc_name);
+
+ // get variable id
+ status = nc_inq_varid(nc_id, var_name, &var_id);
+ check_nc_status(status, "Error getting variable id %s in %s", var_name,
+ nc_name);
+
+ // get type ID
+ status = nc_inq_var(nc_id, var_id, NULL, &xtypep, NULL, NULL, NULL);
+ check_nc_status(status, "Error getting variable type %s in %s", var_name,
+ nc_name);
+
+ // close the netcdf file
+ status = nc_close(nc_id);
+ check_nc_status(status, "Error closing %s", nc_name);
+
+ return(xtypep);
+}
diff --git a/vic/drivers/shared_image/src/vic_init_output.c b/vic/drivers/shared_image/src/vic_init_output.c
index 3fb730bb8..e051cbc45 100644
--- a/vic/drivers/shared_image/src/vic_init_output.c
+++ b/vic/drivers/shared_image/src/vic_init_output.c
@@ -224,32 +224,36 @@ initialize_history_file(nc_file_struct *nc,
double *dvar;
- // This could be further refined but for now, I've choosen a file naming
+ // This could be further refined but for now, I've chosen a file naming
// Convention that goes like this:
switch (stream->agg_alarm.freq) {
// If FREQ_NDAYS -- filename = result_dir/prefix.YYYY-MM-DD.nc
case FREQ_NDAYS:
sprintf(stream->filename, "%s/%s.%04d-%02d-%02d.nc",
filenames.result_dir,
- stream->prefix, ref_dmy->year, ref_dmy->month,
- ref_dmy->day);
+ stream->prefix, stream->time_bounds[0].year,
+ stream->time_bounds[0].month,
+ stream->time_bounds[0].day);
break;
case FREQ_NMONTHS:
// If FREQ_NMONTHS -- filename = result_dir/prefix.YYYY-MM.nc
sprintf(stream->filename, "%s/%s.%04d-%02d.nc", filenames.result_dir,
- stream->prefix, ref_dmy->year, ref_dmy->month);
+ stream->prefix, stream->time_bounds[0].year,
+ stream->time_bounds[0].month);
break;
case FREQ_NYEARS:
// If FREQ_NYEARS -- filename = result_dir/prefix.YYYY.nc
sprintf(stream->filename, "%s/%s.%04d.nc", filenames.result_dir,
- stream->prefix, ref_dmy->year);
+ stream->prefix, stream->time_bounds[0].year);
break;
default:
// For all other cases -- filename = result_dir/prefix.YYYY-MM-DD-SSSSS.nc
sprintf(stream->filename, "%s/%s.%04d-%02d-%02d-%05u.nc",
filenames.result_dir,
- stream->prefix, ref_dmy->year, ref_dmy->month,
- ref_dmy->day, ref_dmy->dayseconds);
+ stream->prefix, stream->time_bounds[0].year,
+ stream->time_bounds[0].month,
+ stream->time_bounds[0].day,
+ stream->time_bounds[0].dayseconds);
}
// open the netcdf file
@@ -269,56 +273,56 @@ initialize_history_file(nc_file_struct *nc,
// define netcdf dimensions
status = nc_def_dim(nc->nc_id, "snow_band", nc->band_size,
&(nc->band_dimid));
- check_nc_status(status, "Error defining snow_band dimenension in %s",
+ check_nc_status(status, "Error defining snow_band dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "front", nc->front_size,
&(nc->front_dimid));
- check_nc_status(status, "Error defining front dimenension in %s",
+ check_nc_status(status, "Error defining front dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "frost_area", nc->frost_size,
&(nc->frost_dimid));
- check_nc_status(status, "Error defining frost_area dimenension in %s",
+ check_nc_status(status, "Error defining frost_area dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "nlayer", nc->layer_size,
&(nc->layer_dimid));
- check_nc_status(status, "Error defining nlayer dimenension in %s",
+ check_nc_status(status, "Error defining nlayer dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, global_domain.info.x_dim, nc->ni_size,
&(nc->ni_dimid));
- check_nc_status(status, "Error defining x dimenension in %s",
+ check_nc_status(status, "Error defining x dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, global_domain.info.y_dim, nc->nj_size,
&(nc->nj_dimid));
- check_nc_status(status, "Error defining y dimenension in %s",
+ check_nc_status(status, "Error defining y dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "node", nc->node_size, &(nc->node_dimid));
- check_nc_status(status, "Error defining node dimenension in %s",
+ check_nc_status(status, "Error defining node dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "root_zone", nc->root_zone_size,
&(nc->root_zone_dimid));
- check_nc_status(status, "Error defining root_zone dimenension in %s",
+ check_nc_status(status, "Error defining root_zone dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "veg_class", nc->veg_size,
&(nc->veg_dimid));
- check_nc_status(status, "Error defining veg_class dimenension in %s",
+ check_nc_status(status, "Error defining veg_class dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "time", nc->time_size,
&(nc->time_dimid));
- check_nc_status(status, "Error defining time dimenension in %s",
+ check_nc_status(status, "Error defining time dimension in %s",
stream->filename);
status = nc_def_dim(nc->nc_id, "nv", 2, &(nc->time_bounds_dimid));
- check_nc_status(status, "Error defining time bounds dimenension in %s",
+ check_nc_status(status, "Error defining time bounds dimension in %s",
stream->filename);
// define the netcdf variable time
diff --git a/vic/drivers/shared_image/src/vic_restore.c b/vic/drivers/shared_image/src/vic_restore.c
index c86fce08b..f23cc3f92 100644
--- a/vic/drivers/shared_image/src/vic_restore.c
+++ b/vic/drivers/shared_image/src/vic_restore.c
@@ -61,7 +61,6 @@ vic_restore(void)
// validate state file dimensions and coordinate variables
check_init_state_file();
-
// read state variables
// allocate memory for variables to be stored
@@ -878,8 +877,10 @@ check_init_state_file(void)
{
extern filenames_struct filenames;
extern domain_struct global_domain;
+ extern domain_struct local_domain;
extern option_struct options;
extern soil_con_struct *soil_con;
+ extern int mpi_rank;
int status;
size_t dimlen;
@@ -889,6 +890,8 @@ check_init_state_file(void)
size_t d1start[1];
size_t d2count[2];
size_t d2start[2];
+ size_t d3count[3];
+ size_t d3start[3];
int lon_var_id;
int lat_var_id;
double *dvar;
@@ -901,163 +904,180 @@ check_init_state_file(void)
check_nc_status(status, "Error opening %s", filenames.init_state);
// read and validate dimension lengths
- 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);
- if (dimlen != global_domain.n_ny) {
- log_err("Number of grid rows in state file does not "
- "match parameter file");
- }
- dimlen = get_nc_dimension(filenames.init_state, "veg_class");
- if (dimlen != options.NVEGTYPES) {
- log_err("Number of veg classes in state file does not "
- "match parameter file");
- }
- dimlen = get_nc_dimension(filenames.init_state, "snow_band");
- if (dimlen != options.SNOW_BAND) {
- log_err("Number of snow bands in state file does not "
- "match parameter file");
- }
- dimlen = get_nc_dimension(filenames.init_state, "nlayer");
- if (dimlen != options.Nlayer) {
- log_err("Number of soil layers in state file does not "
- "match parameter file");
- }
- dimlen = get_nc_dimension(filenames.init_state, "frost_area");
- if (dimlen != options.Nfrost) {
- log_err("Number of frost areas in state file does not "
- "match parameter file");
- }
- dimlen = get_nc_dimension(filenames.init_state, "soil_node");
- if (dimlen != options.Nnode) {
- log_err("Number of soil nodes in state file does not "
- "match parameter file");
- }
- if (options.LAKES) {
- dimlen = get_nc_dimension(filenames.init_state, "lake_node");
- if (dimlen != options.NLAKENODES) {
- log_err("Number of lake nodes in state file does not "
+ if (mpi_rank == VIC_MPI_ROOT) {
+ 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);
+ if (dimlen != global_domain.n_ny) {
+ log_err("Number of grid rows in state file does not "
+ "match parameter file");
+ }
+ dimlen = get_nc_dimension(filenames.init_state, "veg_class");
+ if (dimlen != options.NVEGTYPES) {
+ log_err("Number of veg classes in state file does not "
+ "match parameter file");
+ }
+ dimlen = get_nc_dimension(filenames.init_state, "snow_band");
+ if (dimlen != options.SNOW_BAND) {
+ log_err("Number of snow bands in state file does not "
+ "match parameter file");
+ }
+ dimlen = get_nc_dimension(filenames.init_state, "nlayer");
+ if (dimlen != options.Nlayer) {
+ log_err("Number of soil layers in state file does not "
+ "match parameter file");
+ }
+ dimlen = get_nc_dimension(filenames.init_state, "frost_area");
+ if (dimlen != options.Nfrost) {
+ log_err("Number of frost areas in state file does not "
+ "match parameter file");
+ }
+ dimlen = get_nc_dimension(filenames.init_state, "soil_node");
+ if (dimlen != options.Nnode) {
+ log_err("Number of soil nodes in state file does not "
"match parameter file");
}
+ if (options.LAKES) {
+ dimlen = get_nc_dimension(filenames.init_state, "lake_node");
+ if (dimlen != options.NLAKENODES) {
+ log_err("Number of lake nodes in state file does not "
+ "match parameter file");
+ }
+ }
}
// read dimension variables
// lat/lon
- status = nc_inq_varid(nc.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);
- status = nc_inq_varid(nc.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);
- 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(nc.nc_id, lon_var_id,
- d1start, d1count, dvar);
- check_nc_status(status, "Error reading data from \"%s\" in %s",
+ if (mpi_rank == VIC_MPI_ROOT) {
+ status = nc_inq_varid(nc.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);
- // 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,
- 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(nc.nc_id, lat_var_id,
- d1start, d1count, dvar);
- check_nc_status(status, "Error reading data from \"%s\" in %s",
+ status = nc_inq_varid(nc.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);
- // 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]
- .latitude, rtol,
- abs_tol)) {
- log_err("Latitudes in initial state file do not "
- "match parameter file");
+ 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(nc.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);
+ // 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,
+ abs_tol)) {
+ log_err("Longitudes in initial state file do not "
+ "match parameter file");
+ }
}
- }
- free(dvar);
- }
- 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));
- check_alloc_status(dvar, "Memory allocation error");
-
- d2count[0] = global_domain.n_ny;
- d2count[1] = global_domain.n_nx;
- status = nc_get_vara_double(nc.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);
- 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 "
- "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(nc.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);
+ // 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]
+ .latitude, rtol,
+ abs_tol)) {
+ log_err("Latitudes in initial state file do not "
+ "match parameter file");
+ }
}
- }
- status = nc_get_vara_double(nc.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);
- 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 "
- "match parameter file");
+ free(dvar);
+ }
+ 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));
+ check_alloc_status(dvar, "Memory allocation error");
+
+ d2count[0] = global_domain.n_ny;
+ d2count[1] = global_domain.n_nx;
+ status = nc_get_vara_double(nc.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);
+ 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 "
+ "match parameter file");
+ }
+ }
+ status = nc_get_vara_double(nc.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);
+ 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 "
+ "match parameter file");
+ }
}
+ free(dvar);
+ }
+ else {
+ log_err("global_domain.info.n_coord_dims should be 1 or 2");
}
- free(dvar);
- }
- else {
- log_err("global_domain.info.n_coord_dims should be 1 or 2");
}
- // Variables for other dimensions
- d1start[0] = 0;
- d1count[0] = options.Nnode;
-
- // soil thermal node deltas
- dvar = calloc(options.Nnode, sizeof(*dvar));
+ // initialize dvar for soil thermal node deltas and depths
+ dvar = malloc(local_domain.ncells_active * sizeof(*dvar));
check_alloc_status(dvar, "Memory allocation error");
- get_nc_field_double(filenames.init_state, "dz_node",
- d1start, d1count, dvar);
- for (i = 0; i < options.Nnode; i++) {
- if (dvar[i] != soil_con[0].dz_node[i]) {
- log_err("Soil node intervals in state file do not match "
- "those computed by VIC");
+ // soil thermal node deltas (dimension: node, lat, lon)
+ d3start[0] = 0;
+ d3start[1] = 0;
+ d3start[2] = 0;
+ d3count[0] = 1;
+ d3count[1] = global_domain.n_ny;
+ d3count[2] = global_domain.n_nx;
+ for (j = 0; j < options.Nnode; j++) {
+ d3start[0] = j;
+ get_scatter_nc_field_double(filenames.init_state,
+ "dz_node",
+ d3start, d3count, dvar);
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ if (dvar[i] != soil_con[i].dz_node[j]) {
+ log_err("Soil node intervals in state file do not match "
+ "those computed by VIC");
+ }
}
}
- free(dvar);
// soil thermal node depths
- dvar = calloc(options.Nnode, sizeof(*dvar));
- check_alloc_status(dvar, "Memory allocation error");
-
- get_nc_field_double(filenames.init_state, "node_depth",
- d1start, d1count, dvar);
- for (i = 0; i < options.Nnode; i++) {
- if (dvar[i] != soil_con[0].Zsum_node[i]) {
- log_err("Soil node depths in state file do not match "
- "those computed by VIC");
+ d3start[0] = 0;
+ d3start[1] = 0;
+ d3start[2] = 0;
+ d3count[0] = 1;
+ d3count[1] = global_domain.n_ny;
+ d3count[2] = global_domain.n_nx;
+ for (j = 0; j < options.Nnode; j++) {
+ d3start[0] = j;
+ get_scatter_nc_field_double(filenames.init_state,
+ "node_depth",
+ d3start, d3count, dvar);
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ if (dvar[i] != soil_con[i].Zsum_node[j]) {
+ log_err("Soil node depths in state file do not match "
+ "those computed by VIC");
+ }
}
}
free(dvar);
diff --git a/vic/drivers/shared_image/src/vic_start.c b/vic/drivers/shared_image/src/vic_start.c
index ca94d0bc4..147647e90 100644
--- a/vic/drivers/shared_image/src/vic_start.c
+++ b/vic/drivers/shared_image/src/vic_start.c
@@ -74,7 +74,8 @@ vic_start(void)
}
// read domain info
- get_global_domain(filenames.domain, &global_domain, false);
+ get_global_domain(filenames.domain, filenames.params,
+ &global_domain);
// add the number of vegetation type to the location info in the
// global domain struct. This just makes life easier
@@ -110,9 +111,6 @@ vic_start(void)
"lake_node");
}
- // Validate the parameters file
- compare_ncdomain_with_global_domain(filenames.params);
-
// Check that model parameters are valid
validate_parameters();
}
diff --git a/vic/drivers/shared_image/src/vic_store.c b/vic/drivers/shared_image/src/vic_store.c
index 79c34db73..cc8d35046 100644
--- a/vic/drivers/shared_image/src/vic_store.c
+++ b/vic/drivers/shared_image/src/vic_store.c
@@ -61,15 +61,13 @@ vic_store(dmy_struct *dmy_current,
set_nc_state_file_info(&nc_state_file);
// only open and initialize the netcdf file on the first thread
+ // create netcdf file for storing model state
+ sprintf(filename, "%s.%04i%02i%02i_%05u.nc",
+ filenames.statefile, global_param.stateyear,
+ global_param.statemonth, global_param.stateday,
+ global_param.statesec);
+ initialize_state_file(filename, &nc_state_file, dmy_current);
if (mpi_rank == VIC_MPI_ROOT) {
- // create netcdf file for storing model state
- sprintf(filename, "%s.%04i%02i%02i_%05u.nc",
- filenames.statefile, global_param.stateyear,
- global_param.statemonth, global_param.stateday,
- global_param.statesec);
-
- initialize_state_file(filename, &nc_state_file, dmy_current);
-
debug("writing state file: %s", filename);
}
@@ -1526,9 +1524,11 @@ initialize_state_file(char *filename,
{
extern option_struct options;
extern domain_struct global_domain;
+ extern domain_struct local_domain;
extern global_param_struct global_param;
extern metadata_struct state_metadata[N_STATE_VARS];
extern soil_con_struct *soil_con;
+ extern int mpi_rank;
int status;
int dimids[MAXDIMS];
@@ -1556,93 +1556,97 @@ initialize_state_file(char *filename,
double time_num;
// open the netcdf file
- status = nc_create(filename, get_nc_mode(options.STATE_FORMAT),
- &(nc_state_file->nc_id));
- check_nc_status(status, "Error creating %s", filename);
- nc_state_file->open = true;
-
- // Set netcdf file global attributes
- set_global_nc_attributes(nc_state_file->nc_id, NC_STATE_FILE);
-
- // set the NC_FILL attribute
- status = nc_set_fill(nc_state_file->nc_id, NC_FILL, &old_fill_mode);
- 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,
- &(nc_state_file->time_dimid));
- 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,
- "standard_name", strlen("time"), "time");
- check_nc_status(status, "Error adding attribute in %s", filename);
-
- // adding units attribute to time variable
- str_from_time_units(global_param.time_units, unit_str);
-
- 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,
- "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,
- "calendar", strlen(str), str);
- 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,
- nc_state_file->ni_size, &(nc_state_file->ni_dimid));
- check_nc_status(status, "Error defining \"%s\" in %s",
- global_domain.info.x_dim,
- filename);
-
- status = nc_def_dim(nc_state_file->nc_id, global_domain.info.y_dim,
- nc_state_file->nj_size, &(nc_state_file->nj_dimid));
- check_nc_status(status, "Error defining \"%s\" in %s",
- global_domain.info.y_dim,
- filename);
-
- status = nc_def_dim(nc_state_file->nc_id, "veg_class",
- 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",
- nc_state_file->band_size,
- &(nc_state_file->band_dimid));
- check_nc_status(status, "Error defining snow_band in %s", filename);
-
- status = nc_def_dim(nc_state_file->nc_id, "nlayer",
- nc_state_file->layer_size,
- &(nc_state_file->layer_dimid));
- check_nc_status(status, "Error defining nlayer in %s", filename);
-
- status = nc_def_dim(nc_state_file->nc_id, "frost_area",
- nc_state_file->frost_size,
- &(nc_state_file->frost_dimid));
- check_nc_status(status, "Error defining frost_area in %s", filename);
-
- status = nc_def_dim(nc_state_file->nc_id, "soil_node",
- nc_state_file->node_size,
- &(nc_state_file->node_dimid));
- check_nc_status(status, "Error defining soil_node in %s", filename);
-
- if (options.LAKES) {
- status = nc_def_dim(nc_state_file->nc_id, "lake_node",
- nc_state_file->lake_node_size,
- &(nc_state_file->lake_node_dimid));
- check_nc_status(status, "Error defining lake_node in %s", filename);
+ if (mpi_rank == VIC_MPI_ROOT) {
+ status = nc_create(filename, get_nc_mode(options.STATE_FORMAT),
+ &(nc_state_file->nc_id));
+ check_nc_status(status, "Error creating %s", filename);
+ nc_state_file->open = true;
}
- set_nc_state_var_info(nc_state_file);
+ if (mpi_rank == VIC_MPI_ROOT) {
+ // Set netcdf file global attributes
+ set_global_nc_attributes(nc_state_file->nc_id, NC_STATE_FILE);
+
+ // set the NC_FILL attribute
+ status = nc_set_fill(nc_state_file->nc_id, NC_FILL, &old_fill_mode);
+ 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,
+ &(nc_state_file->time_dimid));
+ 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,
+ "standard_name", strlen("time"), "time");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+
+ // adding units attribute to time variable
+ str_from_time_units(global_param.time_units, unit_str);
+
+ 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,
+ "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,
+ "calendar", strlen(str), str);
+ 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,
+ nc_state_file->ni_size, &(nc_state_file->ni_dimid));
+ check_nc_status(status, "Error defining \"%s\" in %s",
+ global_domain.info.x_dim,
+ filename);
+
+ status = nc_def_dim(nc_state_file->nc_id, global_domain.info.y_dim,
+ nc_state_file->nj_size, &(nc_state_file->nj_dimid));
+ check_nc_status(status, "Error defining \"%s\" in %s",
+ global_domain.info.y_dim,
+ filename);
+
+ status = nc_def_dim(nc_state_file->nc_id, "veg_class",
+ 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",
+ nc_state_file->band_size,
+ &(nc_state_file->band_dimid));
+ check_nc_status(status, "Error defining snow_band in %s", filename);
+
+ status = nc_def_dim(nc_state_file->nc_id, "nlayer",
+ nc_state_file->layer_size,
+ &(nc_state_file->layer_dimid));
+ check_nc_status(status, "Error defining nlayer in %s", filename);
+
+ status = nc_def_dim(nc_state_file->nc_id, "frost_area",
+ nc_state_file->frost_size,
+ &(nc_state_file->frost_dimid));
+ check_nc_status(status, "Error defining frost_area in %s", filename);
+
+ status = nc_def_dim(nc_state_file->nc_id, "soil_node",
+ nc_state_file->node_size,
+ &(nc_state_file->node_dimid));
+ check_nc_status(status, "Error defining soil_node in %s", filename);
+
+ if (options.LAKES) {
+ status = nc_def_dim(nc_state_file->nc_id, "lake_node",
+ nc_state_file->lake_node_size,
+ &(nc_state_file->lake_node_dimid));
+ check_nc_status(status, "Error defining lake_node in %s", filename);
+ }
+
+ set_nc_state_var_info(nc_state_file);
+ }
// initialize dimids to invalid values
for (i = 0; i < MAXDIMS; i++) {
@@ -1653,402 +1657,452 @@ initialize_state_file(char *filename,
// write dimension variables
// Coordinate variables
- ndims = global_domain.info.n_coord_dims;
- dstart[0] = 0;
- dstart[1] = 0;
-
- if (global_domain.info.n_coord_dims == 1) {
- dimids[0] = nc_state_file->ni_dimid;
- dcount[0] = nc_state_file->ni_size;
- }
- else if (global_domain.info.n_coord_dims == 2) {
- dimids[0] = nc_state_file->nj_dimid;
- dcount[0] = nc_state_file->nj_size;
-
- dimids[1] = nc_state_file->ni_dimid;
- dcount[1] = nc_state_file->ni_size;
- }
- else {
- log_err("COORD_DIMS_OUT should be 1 or 2");
+ if (mpi_rank == VIC_MPI_ROOT) {
+ ndims = global_domain.info.n_coord_dims;
+ dstart[0] = 0;
+ dstart[1] = 0;
+
+ if (global_domain.info.n_coord_dims == 1) {
+ dimids[0] = nc_state_file->ni_dimid;
+ dcount[0] = nc_state_file->ni_size;
+ }
+ else if (global_domain.info.n_coord_dims == 2) {
+ dimids[0] = nc_state_file->nj_dimid;
+ dcount[0] = nc_state_file->nj_size;
+
+ dimids[1] = nc_state_file->ni_dimid;
+ dcount[1] = nc_state_file->ni_size;
+ }
+ else {
+ log_err("COORD_DIMS_OUT should be 1 or 2");
+ }
}
// define the netcdf variable longitude
- status = nc_def_var(nc_state_file->nc_id, global_domain.info.lon_var,
- NC_DOUBLE, ndims, dimids, &(lon_var_id));
- check_nc_status(status, "Error defining lon variable in %s", filename);
-
- status = nc_put_att_text(nc_state_file->nc_id, lon_var_id, "long_name", strlen(
- "longitude"), "longitude");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, lon_var_id, "units", strlen(
- "degrees_east"), "degrees_east");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, lon_var_id,
- "standard_name", strlen(
- "longitude"), "longitude");
- check_nc_status(status, "Error adding attribute in %s", filename);
-
- if (global_domain.info.n_coord_dims == 1) {
- dimids[0] = nc_state_file->nj_dimid;
- dcount[0] = nc_state_file->nj_size;
- }
-
- // define the netcdf variable latitude
- status = nc_def_var(nc_state_file->nc_id, global_domain.info.lat_var,
- NC_DOUBLE, ndims, dimids, &(lat_var_id));
- check_nc_status(status, "Error defining lat variable (%s) in %s",
- global_domain.info.lat_var, filename);
- status = nc_put_att_text(nc_state_file->nc_id, lat_var_id, "long_name", strlen(
- "latitude"), "latitude");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, lat_var_id, "units", strlen(
- "degrees_north"), "degrees_north");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, lat_var_id,
- "standard_name", strlen("latitude"),
- "latitude");
- check_nc_status(status, "Error adding attribute in %s", filename);
- for (i = 0; i < MAXDIMS; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
- }
-
- // veg_class
- dimids[0] = nc_state_file->veg_dimid;
- status = nc_def_var(nc_state_file->nc_id, "veg_class",
- NC_INT, 1, dimids, &(veg_var_id));
- check_nc_status(status, "Error defining veg_class variable in %s",
- filename);
- status = nc_put_att_text(nc_state_file->nc_id, veg_var_id, "long_name",
- 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"),
- "vegetation_class_number");
- check_nc_status(status, "Error adding attribute in %s", filename);
- dimids[0] = -1;
-
- // snow_band
- dimids[0] = nc_state_file->band_dimid;
- status = nc_def_var(nc_state_file->nc_id, "snow_band",
- NC_INT, 1, dimids, &(snow_band_var_id));
- check_nc_status(status, "Error defining snow_band variable in %s",
- filename);
- status = nc_put_att_text(nc_state_file->nc_id, snow_band_var_id,
- "long_name",
- strlen("snow_band"), "snow_band");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, snow_band_var_id,
- "standard_name",
- strlen("snow_elevation_band_number"),
- "snow_elevation_band_number");
- check_nc_status(status, "Error adding attribute in %s", filename);
- dimids[0] = -1;
-
- // layer
- dimids[0] = nc_state_file->layer_dimid;
- 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",
- 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,
- "standard_name", strlen("soil_layer_number"),
- "soil_layer_number");
- check_nc_status(status, "Error adding attribute in %s", filename);
- dimids[0] = -1;
-
- // frost_area
- dimids[0] = nc_state_file->frost_dimid;
- status = nc_def_var(nc_state_file->nc_id, "frost_area", NC_INT, 1,
- dimids, &(frost_area_var_id));
- check_nc_status(status, "Error defining frost_area variable in %s",
- filename);
- status = nc_put_att_text(nc_state_file->nc_id, frost_area_var_id,
- "long_name",
- strlen("frost_area"), "frost_area");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, frost_area_var_id,
- "standard_name", strlen("frost_area_number"),
- "frost_area_number");
- check_nc_status(status, "Error adding attribute in %s", filename);
- dimids[0] = -1;
-
- // dz_node
- dimids[0] = nc_state_file->node_dimid;
- status = nc_def_var(nc_state_file->nc_id, "dz_node", NC_DOUBLE, 1,
- 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",
- 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,
- "standard_name", strlen(
- "soil_thermal_node_spacing"),
- "soil_thermal_node_spacing");
- check_nc_status(status, "Error adding attribute in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, dz_node_var_id, "units",
- strlen("m"), "m");
- check_nc_status(status, "Error adding attribute in %s", filename);
- dimids[0] = -1;
-
- // node_depth
- dimids[0] = nc_state_file->node_dimid;
- status = nc_def_var(nc_state_file->nc_id, "node_depth", NC_DOUBLE, 1,
- dimids, &(node_depth_var_id));
- check_nc_status(status, "Error defining node variable in %s", filename);
- status = nc_put_att_text(nc_state_file->nc_id, node_depth_var_id,
- "long_name",
- 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"),
- "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",
- strlen("m"), "m");
- check_nc_status(status, "Error adding attribute in %s", filename);
- dimids[0] = -1;
-
- if (options.LAKES) {
- // lake_node
- 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);
- status = nc_put_att_text(nc_state_file->nc_id, lake_node_var_id,
+ if (mpi_rank == VIC_MPI_ROOT) {
+ status = nc_def_var(nc_state_file->nc_id, global_domain.info.lon_var,
+ NC_DOUBLE, ndims, dimids, &(lon_var_id));
+ check_nc_status(status, "Error defining lon variable in %s", filename);
+
+ status = nc_put_att_text(nc_state_file->nc_id, lon_var_id, "long_name", strlen(
+ "longitude"), "longitude");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, lon_var_id, "units", strlen(
+ "degrees_east"), "degrees_east");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, lon_var_id,
+ "standard_name", strlen(
+ "longitude"), "longitude");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+
+ if (global_domain.info.n_coord_dims == 1) {
+ dimids[0] = nc_state_file->nj_dimid;
+ dcount[0] = nc_state_file->nj_size;
+ }
+
+ // define the netcdf variable latitude
+ status = nc_def_var(nc_state_file->nc_id, global_domain.info.lat_var,
+ NC_DOUBLE, ndims, dimids, &(lat_var_id));
+ check_nc_status(status, "Error defining lat variable (%s) in %s",
+ global_domain.info.lat_var, filename);
+ status = nc_put_att_text(nc_state_file->nc_id, lat_var_id, "long_name", strlen(
+ "latitude"), "latitude");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, lat_var_id, "units", strlen(
+ "degrees_north"), "degrees_north");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, lat_var_id,
+ "standard_name", strlen("latitude"),
+ "latitude");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ for (i = 0; i < MAXDIMS; i++) {
+ dimids[i] = -1;
+ dcount[i] = 0;
+ }
+
+ // veg_class
+ dimids[0] = nc_state_file->veg_dimid;
+ status = nc_def_var(nc_state_file->nc_id, "veg_class",
+ NC_INT, 1, dimids, &(veg_var_id));
+ check_nc_status(status, "Error defining veg_class variable in %s",
+ filename);
+ status = nc_put_att_text(nc_state_file->nc_id, veg_var_id, "long_name",
+ 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"),
+ "vegetation_class_number");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ dimids[0] = -1;
+
+ // snow_band
+ dimids[0] = nc_state_file->band_dimid;
+ status = nc_def_var(nc_state_file->nc_id, "snow_band",
+ NC_INT, 1, dimids, &(snow_band_var_id));
+ check_nc_status(status, "Error defining snow_band variable in %s",
+ filename);
+ status = nc_put_att_text(nc_state_file->nc_id, snow_band_var_id,
+ "long_name",
+ strlen("snow_band"), "snow_band");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, snow_band_var_id,
+ "standard_name",
+ strlen("snow_elevation_band_number"),
+ "snow_elevation_band_number");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ dimids[0] = -1;
+
+ // layer
+ dimids[0] = nc_state_file->layer_dimid;
+ 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",
+ 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,
+ "standard_name", strlen("soil_layer_number"),
+ "soil_layer_number");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ dimids[0] = -1;
+
+ // frost_area
+ dimids[0] = nc_state_file->frost_dimid;
+ status = nc_def_var(nc_state_file->nc_id, "frost_area", NC_INT, 1,
+ dimids, &(frost_area_var_id));
+ check_nc_status(status, "Error defining frost_area variable in %s",
+ filename);
+ status = nc_put_att_text(nc_state_file->nc_id, frost_area_var_id,
"long_name",
- strlen("lake_node"), "lake_node");
+ strlen("frost_area"), "frost_area");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, frost_area_var_id,
+ "standard_name", strlen("frost_area_number"),
+ "frost_area_number");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ dimids[0] = -1;
+
+ // dz_node (dimension: node, lat, lon)
+ dimids[0] = nc_state_file->node_dimid;
+ dimids[1] = nc_state_file->nj_dimid;
+ dimids[2] = nc_state_file->ni_dimid;
+ 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",
+ 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,
- "standard_name", strlen("lake_node_number"),
- "lake_node_number");
+ "standard_name", strlen(
+ "soil_thermal_node_spacing"),
+ "soil_thermal_node_spacing");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, dz_node_var_id, "units",
+ strlen("m"), "m");
check_nc_status(status, "Error adding attribute in %s", filename);
dimids[0] = -1;
+ dimids[1] = -1;
+ dimids[2] = -1;
+
+ // node_depth (dimension: node, lat, lon)
+ dimids[0] = nc_state_file->node_dimid;
+ dimids[1] = nc_state_file->nj_dimid;
+ dimids[2] = nc_state_file->ni_dimid;
+ status = nc_def_var(nc_state_file->nc_id, "node_depth", NC_DOUBLE, 3,
+ dimids, &(node_depth_var_id));
+ check_nc_status(status, "Error defining node variable in %s", filename);
+ status = nc_put_att_text(nc_state_file->nc_id, node_depth_var_id,
+ "long_name",
+ 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"),
+ "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",
+ strlen("m"), "m");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ dimids[0] = -1;
+ dimids[1] = -1;
+ dimids[2] = -1;
+
+ if (options.LAKES) {
+ // lake_node
+ 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);
+ 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"),
+ "lake_node_number");
+ check_nc_status(status, "Error adding attribute in %s", filename);
+ dimids[0] = -1;
+ }
}
// Define state variables
- for (i = 0; i < N_STATE_VARS; i++) {
- if (strcasecmp(state_metadata[i].varname, MISSING_S) == 0) {
- // skip variables not set in set_state_meta_data_info
- continue;
- }
-
- // create the variable
- status = nc_def_var(nc_state_file->nc_id, state_metadata[i].varname,
- nc_state_file->nc_vars[i].nc_type,
- nc_state_file->nc_vars[i].nc_dims,
- nc_state_file->nc_vars[i].nc_dimids,
- &(nc_state_file->nc_vars[i].nc_varid));
- check_nc_status(status, "Error defining state variable %s in %s",
- state_metadata[i].varname, filename);
-
- // set the fill value attribute
- if (nc_state_file->nc_vars[i].nc_type == NC_DOUBLE) {
- status = nc_put_att_double(nc_state_file->nc_id,
- nc_state_file->nc_vars[i].nc_varid,
- "_FillValue", NC_DOUBLE, 1,
- &(nc_state_file->d_fillvalue));
- }
- else if (nc_state_file->nc_vars[i].nc_type == NC_INT) {
- status = nc_put_att_int(nc_state_file->nc_id,
- nc_state_file->nc_vars[i].nc_varid,
- "_FillValue", NC_INT, 1,
- &(nc_state_file->i_fillvalue));
- }
- else {
- log_err("NC_TYPE %d not supported at this time",
- nc_state_file->nc_vars[i].nc_type);
- }
- check_nc_status(status,
- "Error putting _FillValue attribute to %s in %s",
- state_metadata[i].varname, filename);
-
- // Set string attributes
- 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,
- "standard_name", state_metadata[i].standard_name);
- 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,
- "description", state_metadata[i].description);
+ if (mpi_rank == VIC_MPI_ROOT) {
+ for (i = 0; i < N_STATE_VARS; i++) {
+ if (strcasecmp(state_metadata[i].varname, MISSING_S) == 0) {
+ // skip variables not set in set_state_meta_data_info
+ continue;
+ }
+
+ // create the variable
+ status = nc_def_var(nc_state_file->nc_id, state_metadata[i].varname,
+ nc_state_file->nc_vars[i].nc_type,
+ nc_state_file->nc_vars[i].nc_dims,
+ nc_state_file->nc_vars[i].nc_dimids,
+ &(nc_state_file->nc_vars[i].nc_varid));
+ check_nc_status(status, "Error defining state variable %s in %s",
+ state_metadata[i].varname, filename);
+
+ // set the fill value attribute
+ if (nc_state_file->nc_vars[i].nc_type == NC_DOUBLE) {
+ status = nc_put_att_double(nc_state_file->nc_id,
+ nc_state_file->nc_vars[i].nc_varid,
+ "_FillValue", NC_DOUBLE, 1,
+ &(nc_state_file->d_fillvalue));
+ }
+ else if (nc_state_file->nc_vars[i].nc_type == NC_INT) {
+ status = nc_put_att_int(nc_state_file->nc_id,
+ nc_state_file->nc_vars[i].nc_varid,
+ "_FillValue", NC_INT, 1,
+ &(nc_state_file->i_fillvalue));
+ }
+ else {
+ log_err("NC_TYPE %d not supported at this time",
+ nc_state_file->nc_vars[i].nc_type);
+ }
+ check_nc_status(status,
+ "Error putting _FillValue attribute to %s in %s",
+ state_metadata[i].varname, filename);
+
+ // Set string attributes
+ 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,
+ "standard_name", state_metadata[i].standard_name);
+ 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,
+ "description", state_metadata[i].description);
+ }
+
+ // leave define mode
+ status = nc_enddef(nc_state_file->nc_id);
+ check_nc_status(status, "Error leaving define mode for %s", filename);
}
- // leave define mode
- status = nc_enddef(nc_state_file->nc_id);
- check_nc_status(status, "Error leaving define mode for %s", filename);
-
// time variable
// advance dmy_current by one timestep because dmy_current is the
// "timestep-beginning" timestamp, but we want the time variable to be
// the end of the current time step
- dt_seconds_to_time_units(global_param.time_units, global_param.dt,
- &offset);
- time_num = date2num(global_param.time_origin_num, dmy_current, 0,
- global_param.calendar, global_param.time_units);
- dtime = time_num + offset;
- // put in netCDF file
- dstart[0] = 0;
- status = nc_put_var1_double(nc_state_file->nc_id,
- nc_state_file->time_varid,
- dstart, &dtime);
- check_nc_status(status, "Error writing time variable");
-
- // populate lat/lon
- if (global_domain.info.n_coord_dims == 1) {
- dvar = calloc(nc_state_file->ni_size, sizeof(*dvar));
- check_alloc_status(dvar, "Memory allocation error");
-
- dcount[0] = nc_state_file->ni_size;
- // implicitly nested loop over ni and nj with j set to 0
- 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,
- dcount, dvar);
- check_nc_status(status, "Error adding data to lon in %s", filename);
- free(dvar);
-
- dvar = calloc(nc_state_file->nj_size, sizeof(*dvar));
- check_alloc_status(dvar, "Memory allocation error");
- dcount[0] = nc_state_file->nj_size;
- // implicitly nested loop over ni and nj with i set to 0;
- // j stride = ni_size
- for (j = 0; j < nc_state_file->nj_size; j++) {
- dvar[j] =
- (double) global_domain.locations[j *
- nc_state_file->ni_size].
- latitude;
- }
-
- 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);
+ if (mpi_rank == VIC_MPI_ROOT) {
+ dt_seconds_to_time_units(global_param.time_units, global_param.dt,
+ &offset);
+ time_num = date2num(global_param.time_origin_num, dmy_current, 0,
+ global_param.calendar, global_param.time_units);
+ dtime = time_num + offset;
+ // put in netCDF file
+ dstart[0] = 0;
+ status = nc_put_var1_double(nc_state_file->nc_id,
+ nc_state_file->time_varid,
+ dstart, &dtime);
+ check_nc_status(status, "Error writing time variable");
}
- else if (global_domain.info.n_coord_dims == 2) {
- dvar = calloc(global_domain.ncells_total, sizeof(*dvar));
- check_alloc_status(dvar, "Memory allocation error");
- for (i = 0; i < global_domain.ncells_total; i++) {
- dvar[i] = (double) global_domain.locations[i].longitude;
+ // populate lat/lon
+ if (mpi_rank == VIC_MPI_ROOT) {
+ if (global_domain.info.n_coord_dims == 1) {
+ dvar = calloc(nc_state_file->ni_size, sizeof(*dvar));
+ check_alloc_status(dvar, "Memory allocation error");
+
+ dcount[0] = nc_state_file->ni_size;
+ // implicitly nested loop over ni and nj with j set to 0
+ 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,
+ dcount, dvar);
+ check_nc_status(status, "Error adding data to lon in %s", filename);
+ free(dvar);
+
+ dvar = calloc(nc_state_file->nj_size, sizeof(*dvar));
+ check_alloc_status(dvar, "Memory allocation error");
+ dcount[0] = nc_state_file->nj_size;
+ // implicitly nested loop over ni and nj with i set to 0;
+ // j stride = ni_size
+ for (j = 0; j < nc_state_file->nj_size; j++) {
+ dvar[j] =
+ (double) global_domain.locations[j *
+ nc_state_file->ni_size].
+ latitude;
+ }
+
+ 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);
+ }
+ else if (global_domain.info.n_coord_dims == 2) {
+ dvar = calloc(global_domain.ncells_total, sizeof(*dvar));
+ check_alloc_status(dvar, "Memory allocation error");
+ dcount[0] = nc_state_file->nj_size;
+ dcount[1] = nc_state_file->ni_size;
+
+ 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,
+ dcount, dvar);
+ check_nc_status(status, "Error adding data to lon in %s", filename);
+
+ for (i = 0; i < global_domain.ncells_total;
+ i++) {
+ dvar[i] = (double) global_domain.locations[i].latitude;
+ }
+ 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);
+
+ free(dvar);
}
- 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);
-
- for (i = 0; i < global_domain.ncells_total;
- i++) {
- dvar[i] = (double) global_domain.locations[i].latitude;
+ else {
+ log_err("COORD_DIMS_OUT should be 1 or 2");
}
- 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);
-
- free(dvar);
- }
- else {
- log_err("COORD_DIMS_OUT should be 1 or 2");
}
// Variables for other dimensions (all 1-dimensional)
- ndims = 1;
-
- // vegetation classes
- dimids[0] = nc_state_file->veg_dimid;
- dcount[0] = nc_state_file->veg_size;
- ivar = malloc(nc_state_file->veg_size * sizeof(*ivar));
- check_alloc_status(ivar, "Memory allocation error");
-
- 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,
- ivar);
- check_nc_status(status, "Error writing veg var id");
- for (i = 0; i < ndims; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
- }
- free(ivar);
-
- // snow bands
- dimids[0] = nc_state_file->band_dimid;
- dcount[0] = nc_state_file->band_size;
- ivar = malloc(nc_state_file->band_size * sizeof(*ivar));
- check_alloc_status(ivar, "Memory allocation error");
-
- for (j = 0; j < nc_state_file->band_size; j++) {
- ivar[j] = (int) j;
- }
- status = nc_put_vara_int(nc_state_file->nc_id, snow_band_var_id, dstart,
- dcount, ivar);
- check_nc_status(status, "Error writing snow band id");
- for (i = 0; i < ndims; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
- }
- free(ivar);
-
- // soil layers
- dimids[0] = nc_state_file->layer_dimid;
- dcount[0] = nc_state_file->layer_size;
- ivar = malloc(nc_state_file->layer_size * sizeof(*ivar));
- check_alloc_status(ivar, "Memory allocation error");
-
- 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,
- ivar);
- check_nc_status(status, "Error writing layer id");
- for (i = 0; i < ndims; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
+ if (mpi_rank == VIC_MPI_ROOT) {
+ ndims = 1;
+
+ // vegetation classes
+ dimids[0] = nc_state_file->veg_dimid;
+ dcount[0] = nc_state_file->veg_size;
+ ivar = malloc(nc_state_file->veg_size * sizeof(*ivar));
+ check_alloc_status(ivar, "Memory allocation error");
+
+ 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,
+ ivar);
+ check_nc_status(status, "Error writing veg var id");
+ for (i = 0; i < ndims; i++) {
+ dimids[i] = -1;
+ dcount[i] = 0;
+ }
+ free(ivar);
+
+ // snow bands
+ dimids[0] = nc_state_file->band_dimid;
+ dcount[0] = nc_state_file->band_size;
+ ivar = malloc(nc_state_file->band_size * sizeof(*ivar));
+ check_alloc_status(ivar, "Memory allocation error");
+
+ for (j = 0; j < nc_state_file->band_size; j++) {
+ ivar[j] = (int) j;
+ }
+ status = nc_put_vara_int(nc_state_file->nc_id, snow_band_var_id, dstart,
+ dcount, ivar);
+ check_nc_status(status, "Error writing snow band id");
+ for (i = 0; i < ndims; i++) {
+ dimids[i] = -1;
+ dcount[i] = 0;
+ }
+ free(ivar);
+
+ // soil layers
+ dimids[0] = nc_state_file->layer_dimid;
+ dcount[0] = nc_state_file->layer_size;
+ ivar = malloc(nc_state_file->layer_size * sizeof(*ivar));
+ check_alloc_status(ivar, "Memory allocation error");
+
+ 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,
+ ivar);
+ check_nc_status(status, "Error writing layer id");
+ for (i = 0; i < ndims; i++) {
+ dimids[i] = -1;
+ dcount[i] = 0;
+ }
+ free(ivar);
+
+ // frost areas
+ dimids[0] = nc_state_file->frost_dimid;
+ dcount[0] = nc_state_file->frost_size;
+ ivar = malloc(nc_state_file->frost_size * sizeof(*ivar));
+ check_alloc_status(ivar, "Memory allocation error");
+
+ 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,
+ dcount, ivar);
+ check_nc_status(status, "Error writing frost id");
+ for (i = 0; i < ndims; i++) {
+ dimids[i] = -1;
+ dcount[i] = 0;
+ }
+ free(ivar);
}
- free(ivar);
-
- // frost areas
- dimids[0] = nc_state_file->frost_dimid;
- dcount[0] = nc_state_file->frost_size;
- ivar = malloc(nc_state_file->frost_size * sizeof(*ivar));
- check_alloc_status(ivar, "Memory allocation error");
- 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,
- dcount, ivar);
- check_nc_status(status, "Error writing frost id");
- for (i = 0; i < ndims; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
+ // initialize dvar for soil thermal node deltas and depths
+ dvar = malloc(local_domain.ncells_active * sizeof(*dvar));
+ check_alloc_status(dvar, "Memory allocation error");
+ // set missing values
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ dvar[i] = nc_state_file->d_fillvalue;
}
- free(ivar);
- // soil thermal node deltas
- dimids[0] = nc_state_file->node_dimid;
- dcount[0] = nc_state_file->node_size;
- status = nc_put_vara_double(nc_state_file->nc_id, dz_node_var_id, dstart,
- dcount, soil_con[0].dz_node);
- check_nc_status(status, "Error writing thermal node deltas");
- for (i = 0; i < ndims; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
+ // soil thermal node deltas (dimension: node, lat, lon)
+ dstart[0] = 0;
+ dstart[1] = 0;
+ dstart[2] = 0;
+ dcount[0] = 1;
+ dcount[1] = nc_state_file->nj_size;
+ dcount[2] = nc_state_file->ni_size;
+ for (j = 0; j < nc_state_file->node_size; j++) {
+ dstart[0] = j;
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ dvar[i] = soil_con[i].dz_node[j];
+ }
+ gather_put_nc_field_double(nc_state_file->nc_id,
+ dz_node_var_id,
+ nc_state_file->d_fillvalue,
+ dstart, dcount, dvar);
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ dvar[i] = nc_state_file->d_fillvalue;
+ }
}
- // soil thermal node depths
- dimids[0] = nc_state_file->node_dimid;
- dcount[0] = nc_state_file->node_size;
- status = nc_put_vara_double(nc_state_file->nc_id, node_depth_var_id, dstart,
- dcount, soil_con[0].Zsum_node);
- check_nc_status(status, "Error writing thermal node depths");
- for (i = 0; i < ndims; i++) {
- dimids[i] = -1;
- dcount[i] = 0;
+ // soil thermal node depths (dimension: node, lat, lon)
+ dstart[0] = 0;
+ dstart[1] = 0;
+ dstart[2] = 0;
+ dcount[0] = 1;
+ dcount[1] = nc_state_file->nj_size;
+ dcount[2] = nc_state_file->ni_size;
+ for (j = 0; j < nc_state_file->node_size; j++) {
+ dstart[0] = j;
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ dvar[i] = soil_con[i].Zsum_node[j];
+ }
+ gather_put_nc_field_double(nc_state_file->nc_id,
+ node_depth_var_id,
+ nc_state_file->d_fillvalue,
+ dstart, dcount, dvar);
+ for (i = 0; i < local_domain.ncells_active; i++) {
+ dvar[i] = nc_state_file->d_fillvalue;
+ }
}
if (options.LAKES) {