Last active
August 29, 2015 14:23
-
-
Save jhamman/b87a5666922cc623b845 to your computer and use it in GitHub Desktop.
Atmospheric Decoupling VIC Changes: RASM.1.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Breaking the land-atmosphere coupling in RASM.1.0 | |
======== | |
To "break" the surface layer in RASM, we need to remove the upper stability limit to the aerodynamic resistance calculation in both `Fixed calc_surf_energy_bal.c` and `SnowPackEnergyBalance`. | |
This limit was established c.RACM33. | |
These changes are shown here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include "vicNl.h" | |
static char vcid[] = | |
"$Id: calc_surf_energy_bal.c,v 4.2 2000/08/16 00:35:28 vicadmin Exp vicadmin $"; | |
/******************************************************************************* | |
calc_surf_energy_bal.c Greg O'Donnell and Keith Cherkauer Sept 9 1997 | |
This function calculates the surface temperature, in the | |
case of no snow cover. Evaporation is computed using the | |
previous ground heat flux, and then used to comput latent heat | |
in the energy balance routine. Surface temperature is found | |
using the Root Brent method (Numerical Recipies). | |
modifications: | |
02-29-00 Included variables needed to compute energy flux | |
through the snow pack. The ground surface energy | |
balance will now be a mixture of snow covered | |
and bare ground, controlled by the snow cover | |
fraction set in solve_snow.c KAC | |
modifications: | |
12/2011 - code reformatting and cleanup | |
BN | |
10/2012 - ported changes for aero_resist_used from VIC 4.0.6 to store | |
the aerodynamic resistance actually used in flux | |
calculations. | |
BN | |
01/2013 - add upper limit to *aero_resist_used of 100 s/m under stable | |
conditions to avoid decoupling between the atmosphere and | |
the land surface. | |
BN | |
*******************************************************************************/ | |
double | |
calc_surf_energy_bal(int rec, | |
int iveg, | |
int nlayer, | |
int Nveg, | |
float dt, | |
int Nnodes, | |
int veg_class, | |
int band, | |
int hour, | |
double ice0, | |
double moist, | |
double dp, | |
double surf_atten, | |
double T0, | |
double shortwave, | |
double longwave, | |
double air_temp, | |
double Le, | |
double Ls, | |
double mu, | |
double displacement, | |
double roughness, | |
double ref_height, | |
double snow_energy, | |
double vapor_flux, | |
double bare_albedo, | |
double *aero_resist, | |
double *aero_resist_used, | |
double *wind, | |
double *rainfall, | |
double *ppt, | |
float *root, | |
atmos_data_struct *atmos, | |
veg_var_struct *veg_var_wet, | |
veg_var_struct *veg_var_dry, | |
energy_bal_struct *energy, | |
snow_data_struct *snow, | |
layer_data_struct *layer_wet, | |
layer_data_struct *layer_dry, | |
soil_con_struct *soil_con, | |
dmy_struct *dmy) | |
{ | |
extern veg_lib_struct *veg_lib; | |
extern option_struct options; | |
char FIRST_SOLN[1]; | |
double T2; | |
double Ts_old; | |
double T1_old; | |
double Tair; | |
double atmos_density; | |
double pz; /* kpa, air pressure, M.Huang*/ | |
double albedo; | |
double emissivity; | |
double kappa1; | |
double kappa2; | |
double Cs1; | |
double Cs2; | |
double D1; | |
double D2; | |
double delta_t; | |
double Vapor; | |
double max_moist; | |
double bubble; | |
double expt; | |
double T1; | |
double snow_depth; | |
double snow_density; | |
double Tsnow_surf; | |
double snow_cover_fraction; | |
double snow_flux; | |
int VEG; | |
double Tsurf; | |
double U; | |
double error; | |
double Wdew[2]; | |
double *T_node; | |
double Tnew_node[MAX_NODES]; | |
double *dz_node; | |
double *kappa_node; | |
double *Cs_node; | |
double *moist_node; | |
double *bubble_node; | |
double *expt_node; | |
double *max_moist_node; | |
double *ice_node; | |
double *alpha; | |
double *beta; | |
double *gamma; | |
layer_data_struct layer[MAX_LAYERS]; | |
double T_lower, T_upper, Terr; | |
/************************************************** | |
Correct Aerodynamic Resistance for Stability | |
**************************************************/ | |
U = wind[0]; | |
/* RACMNOTE: Uncommented. Note that the HUGE_RESIST line should not be | |
triggered since there is already a minimum wind speed - BN - 03/2012 */ | |
if (U > 0.0) { | |
*aero_resist_used = aero_resist[0]/ | |
StabilityCorrection(ref_height, displacement, T0, | |
air_temp, U, roughness); | |
// /* RASMnote - added to avoid decoupling under stable conditions | |
// - BN - 01/2013 */ | |
// if (air_temp > T0 && *aero_resist_used > RA_STABLE_UPPER_LIMIT) { | |
// *aero_resist_used = RA_STABLE_UPPER_LIMIT; | |
// } | |
} | |
else | |
*aero_resist_used = HUGE_RESIST; | |
/************************************************** | |
Compute Evaporation and Transpiration | |
**************************************************/ | |
if (iveg != Nveg) { | |
if (veg_lib[veg_class].LAI[dmy->month - 1] > 0.0) { | |
VEG = TRUE; | |
} | |
else { | |
VEG = FALSE; | |
} | |
} | |
else { | |
VEG = FALSE; | |
} | |
Vapor = vapor_flux / (double)dt / 3600.; | |
/************************************************** | |
Set All Variables For Use | |
**************************************************/ | |
T2 = energy->T[Nnodes - 1]; | |
Ts_old = energy->T[0]; | |
T1_old = energy->T[1]; | |
Tair = air_temp; | |
atmos_density = atmos->density[hour]; | |
pz = atmos->pressure[hour]; /* M.Huang*/ | |
albedo = bare_albedo; | |
emissivity = EMISS; | |
kappa1 = energy->kappa[0]; | |
kappa2 = energy->kappa[1]; | |
Cs1 = energy->Cs[0]; | |
Cs2 = energy->Cs[1]; | |
D1 = soil_con->depth[0]; | |
D2 = soil_con->depth[0]; | |
delta_t = (double)dt * 3600.; | |
max_moist = soil_con->max_moist[0] / (soil_con->depth[0] * 1000.); | |
bubble = soil_con->bubble[0]; | |
expt = soil_con->expt[0]; | |
snow_depth = snow->depth; | |
snow_density = snow->density; | |
Tsnow_surf = snow->surf_temp; | |
snow_cover_fraction = snow->coverage; | |
Wdew[WET] = veg_var_wet->Wdew; | |
if (options.DIST_PRCP) { | |
Wdew[DRY] = veg_var_dry->Wdew; | |
} | |
FIRST_SOLN[0] = TRUE; | |
/************************************************************* | |
Prepare soil node variables for finite difference solution | |
*************************************************************/ | |
if (!options.QUICK_FLUX) { | |
bubble_node = soil_con->bubble_node; | |
expt_node = soil_con->expt_node; | |
max_moist_node = soil_con->max_moist_node; | |
alpha = soil_con->alpha; | |
beta = soil_con->beta; | |
gamma = soil_con->gamma; | |
moist_node = energy->moist; | |
kappa_node = energy->kappa_node; | |
Cs_node = energy->Cs_node; | |
T_node = energy->T; | |
dz_node = soil_con->dz_node; | |
ice_node = energy->ice; | |
} | |
else { | |
bubble_node = NULL; | |
expt_node = NULL; | |
max_moist_node = NULL; | |
alpha = NULL; | |
beta = NULL; | |
gamma = NULL; | |
moist_node = NULL; | |
kappa_node = NULL; | |
Cs_node = NULL; | |
T_node = NULL; | |
dz_node = NULL; | |
ice_node = NULL; | |
} | |
/************************************************** | |
Find Surface Temperature Using Root Brent Method | |
**************************************************/ | |
if (options.FULL_ENERGY) { | |
/** Added for temporary backwards compatability **/ | |
if (snow->swq > 0) { | |
T_lower = 0.; | |
T_upper = energy->T[0] - SURF_DT; | |
} | |
else { | |
T_lower = 0.5 * (energy->T[0] + air_temp) - SURF_DT; | |
T_upper = 0.5 * (energy->T[0] + air_temp) + SURF_DT; | |
} | |
if (T_lower > T_upper) { | |
Terr = T_lower; | |
T_lower = T_upper; | |
T_upper = Terr; | |
} | |
#if QUICK_FS | |
Tsurf = root_brent(T_lower, T_upper, | |
func_surf_energy_bal, T2, Ts_old, T1_old, Tair, | |
*aero_resist_used, atmos_density, pz, shortwave, | |
longwave, albedo, emissivity, kappa1, kappa2, | |
Cs1, Cs2, D1, D2, dp, delta_t, Le, Ls, Vapor, moist, | |
ice0, max_moist, bubble, expt, snow_depth, | |
snow_density, Tsnow_surf, snow_cover_fraction, | |
surf_atten, U, displacement, roughness, ref_height, | |
(double)soil_con->elevation, soil_con->b_infilt, | |
soil_con->max_infil, (double)dt, atmos->vpd[hour], | |
snow_energy, mu, rainfall, Wdew, &energy->grnd_flux, | |
&T1, &energy->latent, &energy->sensible, | |
&energy->deltaH, &energy->snow_flux, &energy->error, | |
soil_con->depth, soil_con->Wcr, soil_con->Wpwp, | |
soil_con->resid_moist, T_node, Tnew_node, dz_node, | |
kappa_node, Cs_node, moist_node, bubble_node, | |
expt_node, max_moist_node, ice_node, alpha, beta, | |
gamma, soil_con->ufwc_table_layer[0], | |
soil_con->ufwc_table_node, root, layer_wet, | |
layer_dry, veg_var_wet, veg_var_dry, VEG, | |
veg_class, dmy->month, Nnodes, | |
FIRST_SOLN, snow->snow, soil_con->FS_ACTIVE); | |
#else | |
Tsurf = root_brent(T_lower, T_upper, | |
func_surf_energy_bal, T2, Ts_old, T1_old, Tair, | |
*aero_resist_used, atmos_density, pz, shortwave, | |
longwave, albedo, emissivity, kappa1, kappa2, | |
Cs1, Cs2, D1, D2, dp, delta_t, Le, Ls, Vapor, moist, | |
ice0, max_moist, bubble, expt, snow_depth, | |
snow_density, Tsnow_surf, snow_cover_fraction, | |
surf_atten, U, displacement, roughness, ref_height, | |
(double)soil_con->elevation, soil_con->b_infilt, | |
soil_con->max_infil, (double)dt, atmos->vpd[hour], | |
snow_energy, mu, rainfall, Wdew, &energy->grnd_flux, | |
&T1, &energy->latent, &energy->sensible, | |
&energy->deltaH, &energy->snow_flux, &energy->error, | |
soil_con->depth, soil_con->Wcr, soil_con->Wpwp, | |
soil_con->resid_moist, T_node, Tnew_node, dz_node, | |
kappa_node, Cs_node, moist_node, bubble_node, | |
expt_node, max_moist_node, ice_node, alpha, beta, | |
gamma, root, layer_wet, layer_dry, veg_var_wet, | |
veg_var_dry, VEG, veg_class, | |
dmy->month, Nnodes, FIRST_SOLN, snow->snow, | |
soil_con->FS_ACTIVE); | |
#endif | |
if (Tsurf <= -9998) { | |
#if QUICK_FS | |
error = error_calc_surf_energy_bal(Tsurf, T2, Ts_old, T1_old, Tair, | |
*aero_resist_used, atmos_density, | |
pz, shortwave, | |
longwave, albedo, emissivity, | |
kappa1, kappa2, Cs1, Cs2, D1, D2, | |
dp, delta_t, Le, Ls, Vapor, | |
moist, ice0, max_moist, bubble, | |
expt, snow_depth, snow_density, | |
Tsnow_surf, snow_cover_fraction, | |
surf_atten, U, displacement, | |
roughness, ref_height, | |
(double)soil_con->elevation, | |
soil_con->b_infilt, | |
soil_con->max_infil, (double)dt, | |
atmos->vpd[hour], snow_energy, | |
mu, rainfall, Wdew, | |
&energy->grnd_flux, | |
&T1, &energy->latent, | |
&energy->sensible, | |
&energy->deltaH, | |
&energy->snow_flux, | |
&energy->error, soil_con->depth, | |
soil_con->Wcr, soil_con->Wpwp, | |
soil_con->resid_moist, T_node, | |
Tnew_node, dz_node, kappa_node, | |
Cs_node, moist_node, bubble_node, | |
expt_node, max_moist_node, | |
ice_node, alpha, beta, gamma, | |
soil_con->ufwc_table_layer[0], | |
soil_con->ufwc_table_node, | |
root, layer_wet, layer_dry, | |
veg_var_wet, veg_var_dry, VEG, | |
veg_class, dmy->month, iveg, | |
Nnodes, FIRST_SOLN, snow->snow, | |
soil_con->FS_ACTIVE); | |
#else | |
error = error_calc_surf_energy_bal(Tsurf, T2, Ts_old, T1_old, Tair, | |
*aero_resist_used, atmos_density, | |
pz, shortwave, | |
longwave, albedo, emissivity, | |
kappa1, kappa2, Cs1, Cs2, D1, D2, | |
dp, delta_t, Le, Ls, Vapor, | |
moist, ice0, max_moist, bubble, | |
expt, snow_depth, snow_density, | |
Tsnow_surf, snow_cover_fraction, | |
surf_atten, U, displacement, | |
roughness, ref_height, | |
(double)soil_con->elevation, | |
soil_con->b_infilt, | |
soil_con->max_infil, (double)dt, | |
atmos->vpd[hour], snow_energy, | |
mu, rainfall, Wdew, | |
&energy->grnd_flux, | |
&T1, &energy->latent, | |
&energy->sensible, | |
&energy->deltaH, | |
&energy->snow_flux, | |
&energy->error, soil_con->depth, | |
soil_con->Wcr, soil_con->Wpwp, | |
soil_con->resid_moist, T_node, | |
Tnew_node, dz_node, kappa_node, | |
Cs_node, moist_node, bubble_node, | |
expt_node, max_moist_node, | |
ice_node, alpha, beta, gamma, | |
root, layer_wet, layer_dry, | |
veg_var_wet, veg_var_dry, VEG, | |
veg_class, dmy->month, iveg, | |
Nnodes, FIRST_SOLN, snow->snow, | |
soil_con->FS_ACTIVE); | |
#endif | |
} | |
} | |
else { | |
/** Frozen soil model run with no surface energy balance **/ | |
Tsurf = Tair; | |
} | |
/************************************************** | |
Recalculate Energy Balance Terms for Final Surface Temperature | |
**************************************************/ | |
#if QUICK_FS | |
error = solve_surf_energy_bal(Tsurf, T2, Ts_old, T1_old, Tair, | |
*aero_resist_used, | |
atmos_density, pz, shortwave, longwave, | |
albedo, emissivity, kappa1, kappa2, Cs1, Cs2, | |
D1, D2, dp, delta_t, Le, Ls, Vapor, moist, | |
ice0, max_moist, bubble, expt, snow_depth, | |
snow_density, Tsnow_surf, | |
snow_cover_fraction, surf_atten, U, | |
displacement, roughness, ref_height, | |
(double)soil_con->elevation, | |
soil_con->b_infilt, soil_con->max_infil, | |
(double)dt, atmos->vpd[hour], snow_energy, mu, | |
rainfall, Wdew, &energy->grnd_flux, | |
&T1, &energy->latent, &energy->sensible, | |
&energy->deltaH, &energy->snow_flux, | |
&energy->error, soil_con->depth, | |
soil_con->Wcr, soil_con->Wpwp, | |
soil_con->resid_moist, T_node, | |
Tnew_node, dz_node, kappa_node, Cs_node, | |
moist_node, bubble_node, expt_node, | |
max_moist_node, ice_node, alpha, beta, gamma, | |
soil_con->ufwc_table_layer[0], | |
soil_con->ufwc_table_node, root, layer_wet, | |
layer_dry, veg_var_wet, veg_var_dry, VEG, | |
veg_class, dmy->month, Nnodes, | |
FIRST_SOLN, snow->snow, | |
soil_con->FS_ACTIVE); | |
#else | |
error = solve_surf_energy_bal(Tsurf, T2, Ts_old, T1_old, Tair, | |
*aero_resist_used, | |
atmos_density, pz, shortwave, longwave, | |
albedo, emissivity, kappa1, kappa2, Cs1, Cs2, | |
D1, D2, dp, delta_t, Le, Ls, Vapor, moist, | |
ice0, max_moist, bubble, expt, snow_depth, | |
snow_density, Tsnow_surf, | |
snow_cover_fraction, surf_atten, U, | |
displacement, roughness, ref_height, | |
(double)soil_con->elevation, | |
soil_con->b_infilt, soil_con->max_infil, | |
(double)dt, atmos->vpd[hour], snow_energy, mu, | |
rainfall, Wdew, &energy->grnd_flux, | |
&T1, &energy->latent, &energy->sensible, | |
&energy->deltaH, &energy->snow_flux, | |
&energy->error, soil_con->depth, | |
soil_con->Wcr, soil_con->Wpwp, | |
soil_con->resid_moist, T_node, | |
Tnew_node, dz_node, kappa_node, Cs_node, | |
moist_node, bubble_node, expt_node, | |
max_moist_node, ice_node, alpha, beta, gamma, | |
root, layer_wet, layer_dry, veg_var_wet, | |
veg_var_dry, VEG, | |
veg_class, dmy->month, Nnodes, FIRST_SOLN, | |
snow->snow, | |
soil_con->FS_ACTIVE); | |
#endif | |
energy->error = error; | |
/*************************************************** | |
Recalculate Soil Moisture and Thermal Properties | |
***************************************************/ | |
if (options.GRND_FLUX) { | |
if (options.QUICK_FLUX) { | |
energy->T[0] = Tsurf; | |
energy->T[1] = T1; | |
} | |
else { | |
finish_frozen_soil_calcs(energy, layer_wet, layer_dry, layer, | |
soil_con, | |
Nnodes, iveg, mu, Tnew_node, kappa_node, | |
Cs_node, | |
moist_node); | |
} | |
} | |
else { | |
energy->T[0] = Tsurf; | |
} | |
/** Store precipitation that reaches the surface */ | |
if (!snow->snow) { | |
if (iveg != Nveg) { | |
if (veg_lib[veg_class].LAI[dmy->month - 1] <= 0.0) { | |
veg_var_wet->throughfall = rainfall[WET]; | |
if (options.DIST_PRCP) { | |
veg_var_dry->throughfall = rainfall[DRY]; | |
} | |
ppt[WET] = veg_var_wet->throughfall; | |
if (options.DIST_PRCP) { | |
ppt[DRY] = veg_var_dry->throughfall; | |
} | |
} | |
else { | |
ppt[WET] = veg_var_wet->throughfall; | |
if (options.DIST_PRCP) { | |
ppt[DRY] = veg_var_dry->throughfall; | |
} | |
} | |
} | |
else { | |
ppt[WET] = rainfall[WET]; | |
if (options.DIST_PRCP) { | |
ppt[DRY] = rainfall[DRY]; | |
} | |
} | |
} | |
/** Store net longwave radiation **/ | |
/* RACMnote: hour == 0 in RASM, so the if {} statement is always executed and | |
the value from which the outgoing is substracted is the value that is | |
stored as bare_energy->longwave in surface_fluxes () -- BN -- 06/2012 */ | |
if (hour < 24) { | |
energy->longwave = longwave - | |
EMISS * STEFAN_B * | |
(Tsurf + KELVIN) * | |
(Tsurf + KELVIN) * | |
(Tsurf + KELVIN) * | |
(Tsurf + KELVIN); | |
} | |
else { | |
energy->longwave = longwave; | |
} | |
/** Store surface albedo **/ | |
energy->albedo = bare_albedo; | |
/** Store net shortwave radiation **/ | |
energy->shortwave = (1. - energy->albedo) * shortwave; | |
/** Return soil surface temperature **/ | |
return (Tsurf); | |
} | |
double | |
solve_surf_energy_bal(double Tsurf, | |
...) | |
{ | |
va_list ap; | |
double error; | |
va_start(ap, Tsurf); | |
error = func_surf_energy_bal(Tsurf, ap); | |
va_end(ap); | |
return error; | |
} | |
double | |
error_calc_surf_energy_bal(double Tsurf, | |
...) | |
{ | |
va_list ap; | |
double error; | |
va_start(ap, Tsurf); | |
error = error_print_surf_energy_bal(Tsurf, ap); | |
va_end(ap); | |
return error; | |
} | |
double | |
error_print_surf_energy_bal(double Ts, | |
va_list ap) | |
{ | |
extern option_struct options; | |
/** Thermal Properties **/ | |
double T2; | |
double Ts_old; | |
double T1_old; | |
double Tair; | |
double ra; | |
double atmos_density; | |
double pz; /* kpa, air pressure, M.Huang*/ | |
double shortwave; | |
double longwave; | |
double albedo; | |
double emissivity; | |
double kappa1; | |
double kappa2; | |
double Cs1; | |
double Cs2; | |
double D1; | |
double D2; | |
double dp; | |
double delta_t; | |
double Le; | |
double Ls; | |
double Vapor; | |
double moist; | |
double ice0; | |
double max_moist; | |
double bubble; | |
double expt; | |
double snow_depth; | |
double snow_density; | |
double Tsnow_surf; | |
double snow_cover_fraction; | |
double surf_atten; | |
double wind; | |
double displacement; | |
double roughness; | |
double ref_height; | |
double elevation; | |
double b_infilt; | |
double max_infil; | |
double dt; | |
double vpd; | |
double snow_energy; | |
double mu; | |
double *rainfall; | |
double *Wdew; | |
double *grnd_flux; | |
double *T1; | |
double *latent_heat; | |
double *sensible_heat; | |
double *deltaH; | |
double *snow_flux; | |
double *store_error; | |
double *depth; | |
double *Wcr; | |
double *Wpwp; | |
double *resid_moist; | |
double *T_node; | |
double *Tnew_node; | |
double *dz_node; | |
double *kappa_node; | |
double *Cs_node; | |
double *moist_node; | |
double *bubble_node; | |
double *expt_node; | |
double *max_moist_node; | |
double *ice_node; | |
double *alpha; | |
double *beta; | |
double *gamma; | |
#if QUICK_FS | |
double **ufwc_table_layer; | |
double ***ufwc_table_node; | |
#endif | |
float *root; | |
layer_data_struct *layer_wet; | |
layer_data_struct *layer_dry; | |
veg_var_struct *veg_var_wet; | |
veg_var_struct *veg_var_dry; | |
int VEG; | |
int veg_class; | |
int month; | |
int iveg; | |
int Nnodes; | |
char *FIRST_SOLN; | |
int SNOWING; | |
int FS_ACTIVE; | |
int i; | |
/* Initialize Variables */ | |
T2 = (double) va_arg(ap, double); | |
Ts_old = (double) va_arg(ap, double); | |
T1_old = (double) va_arg(ap, double); | |
Tair = (double) va_arg(ap, double); | |
ra = (double) va_arg(ap, double); | |
atmos_density = (double) va_arg(ap, double); | |
pz = (double) va_arg(ap, double); /* M.Huang*/ | |
shortwave = (double) va_arg(ap, double); | |
longwave = (double) va_arg(ap, double); | |
albedo = (double) va_arg(ap, double); | |
emissivity = (double) va_arg(ap, double); | |
kappa1 = (double) va_arg(ap, double); | |
kappa2 = (double) va_arg(ap, double); | |
Cs1 = (double) va_arg(ap, double); | |
Cs2 = (double) va_arg(ap, double); | |
D1 = (double) va_arg(ap, double); | |
D2 = (double) va_arg(ap, double); | |
dp = (double) va_arg(ap, double); | |
delta_t = (double) va_arg(ap, double); | |
Le = (double) va_arg(ap, double); | |
Ls = (double) va_arg(ap, double); | |
Vapor = (double) va_arg(ap, double); | |
moist = (double) va_arg(ap, double); | |
ice0 = (double) va_arg(ap, double); | |
max_moist = (double) va_arg(ap, double); | |
bubble = (double) va_arg(ap, double); | |
expt = (double) va_arg(ap, double); | |
snow_depth = (double) va_arg(ap, double); | |
snow_density = (double) va_arg(ap, double); | |
Tsnow_surf = (double) va_arg(ap, double); | |
snow_cover_fraction = (double) va_arg(ap, double); | |
surf_atten = (double) va_arg(ap, double); | |
wind = (double) va_arg(ap, double); | |
displacement = (double) va_arg(ap, double); | |
roughness = (double) va_arg(ap, double); | |
ref_height = (double) va_arg(ap, double); | |
elevation = (double) va_arg(ap, double); | |
b_infilt = (double) va_arg(ap, double); | |
max_infil = (double) va_arg(ap, double); | |
dt = (double) va_arg(ap, double); | |
vpd = (double) va_arg(ap, double); | |
snow_energy = (double) va_arg(ap, double); | |
mu = (double) va_arg(ap, double); | |
rainfall = (double *) va_arg(ap, double *); | |
Wdew = (double *) va_arg(ap, double *); | |
grnd_flux = (double *) va_arg(ap, double *); | |
T1 = (double *) va_arg(ap, double *); | |
latent_heat = (double *) va_arg(ap, double *); | |
sensible_heat = (double *) va_arg(ap, double *); | |
deltaH = (double *) va_arg(ap, double *); | |
snow_flux = (double *) va_arg(ap, double *); | |
store_error = (double *) va_arg(ap, double *); | |
depth = (double *) va_arg(ap, double *); | |
Wcr = (double *) va_arg(ap, double *); | |
Wpwp = (double *) va_arg(ap, double *); | |
resid_moist = (double *) va_arg(ap, double *); | |
T_node = (double *) va_arg(ap, double *); | |
Tnew_node = (double *) va_arg(ap, double *); | |
dz_node = (double *) va_arg(ap, double *); | |
kappa_node = (double *) va_arg(ap, double *); | |
Cs_node = (double *) va_arg(ap, double *); | |
moist_node = (double *) va_arg(ap, double *); | |
bubble_node = (double *) va_arg(ap, double *); | |
expt_node = (double *) va_arg(ap, double *); | |
max_moist_node = (double *) va_arg(ap, double *); | |
ice_node = (double *) va_arg(ap, double *); | |
alpha = (double *) va_arg(ap, double *); | |
beta = (double *) va_arg(ap, double *); | |
gamma = (double *) va_arg(ap, double *); | |
#if QUICK_FS | |
ufwc_table_layer = (double **) va_arg(ap, double **); | |
ufwc_table_node = (double ***) va_arg(ap, double ***); | |
#endif | |
root = (float *) va_arg(ap, float *); | |
layer_wet = (layer_data_struct *) va_arg(ap, layer_data_struct *); | |
layer_dry = (layer_data_struct *) va_arg(ap, layer_data_struct *); | |
veg_var_wet = (veg_var_struct *) va_arg(ap, veg_var_struct *); | |
veg_var_dry = (veg_var_struct *) va_arg(ap, veg_var_struct *); | |
VEG = (int) va_arg(ap, int); | |
veg_class = (int) va_arg(ap, int); | |
month = (int) va_arg(ap, int); | |
iveg = (int) va_arg(ap, int); | |
Nnodes = (int) va_arg(ap, int); | |
FIRST_SOLN = (char *) va_arg(ap, char *); | |
SNOWING = (int) va_arg(ap, int); | |
FS_ACTIVE = (int) va_arg(ap, int); | |
/* Print Variables */ | |
fprintf(stderr, "T2 = %f\n", T2); | |
fprintf(stderr, "Ts_old = %f\n", Ts_old); | |
fprintf(stderr, "T1_old = %f\n", T1_old); | |
fprintf(stderr, "Tair = %f\n", Tair); | |
fprintf(stderr, "ra = %f\n", ra); | |
fprintf(stderr, "atmos_density = %f\n", atmos_density); | |
fprintf(stderr, "air pressure = %f\n", pz); /* M.Huang*/ | |
fprintf(stderr, "shortwave = %f\n", shortwave); | |
fprintf(stderr, "longwave = %f\n", longwave); | |
fprintf(stderr, "albedo = %f\n", albedo); | |
fprintf(stderr, "emissivity = %f\n", emissivity); | |
fprintf(stderr, "kappa1 = %f\n", kappa1); | |
fprintf(stderr, "kappa2 = %f\n", kappa2); | |
fprintf(stderr, "Cs1 = %f\n", Cs1); | |
fprintf(stderr, "Cs2 = %f\n", Cs2); | |
fprintf(stderr, "D1 = %f\n", D1); | |
fprintf(stderr, "D2 = %f\n", D2); | |
fprintf(stderr, "dp = %f\n", dp); | |
fprintf(stderr, "delta_t = %f\n", delta_t); | |
fprintf(stderr, "Le = %f\n", Le); | |
fprintf(stderr, "Ls = %f\n", Ls); | |
fprintf(stderr, "Vapor = %f\n", Vapor); | |
fprintf(stderr, "moist = %f\n", moist); | |
fprintf(stderr, "ice0 = %f\n", ice0); | |
fprintf(stderr, "max_moist = %f\n", max_moist); | |
fprintf(stderr, "bubble = %f\n", bubble); | |
fprintf(stderr, "expt = %f\n", expt); | |
fprintf(stderr, "surf_atten = %f\n", surf_atten); | |
fprintf(stderr, "wind = %f\n", wind); | |
fprintf(stderr, "displacement = %f\n", displacement); | |
fprintf(stderr, "roughness = %f\n", roughness); | |
fprintf(stderr, "ref_height = %f\n", ref_height); | |
fprintf(stderr, "elevation = %f\n", elevation); | |
fprintf(stderr, "b_infilt = %f\n", b_infilt); | |
fprintf(stderr, "max_infil = %f\n", max_infil); | |
fprintf(stderr, "dt = %f\n", dt); | |
fprintf(stderr, "vpd = %f\n", vpd); | |
fprintf(stderr, "snow_energy = %f\n", snow_energy); | |
fprintf(stderr, "mu = %f\n", mu); | |
fprintf(stderr, "rainfall = %f\n", rainfall[0]); | |
fprintf(stderr, "Wdew = %f\n", Wdew[0]); | |
fprintf(stderr, "grnd_flux = %f\n", grnd_flux[0]); | |
fprintf(stderr, "T1 = %f\n", T1[0]); | |
fprintf(stderr, "latent_heat = %f\n", latent_heat[0]); | |
fprintf(stderr, "sensible_heat = %f\n", sensible_heat[0]); | |
fprintf(stderr, "deltaH = %f\n", deltaH[0]); | |
fprintf(stderr, "store_error = %f\n", store_error[0]); | |
fprintf(stderr, "depth = %f\n", depth[0]); | |
fprintf(stderr, "Wcr = %f\n", Wcr[0]); | |
fprintf(stderr, "Wpwp = %f\n", Wpwp[0]); | |
fprintf(stderr, "Residual Moisture = %f\n", resid_moist[0]); | |
fprintf(stderr, "VEG = %i\n", VEG); | |
fprintf(stderr, "veg_class = %i\n", veg_class); | |
fprintf(stderr, "month = %i\n", month); | |
write_layer(layer_wet, iveg, options.Nlayer, depth); | |
if (options.DIST_PRCP) { | |
write_layer(layer_dry, iveg, options.Nlayer, depth); | |
} | |
write_vegvar(&(veg_var_wet[0]), iveg); | |
if (options.DIST_PRCP) { | |
write_vegvar(&(veg_var_dry[0]), iveg); | |
} | |
if (!options.QUICK_FLUX) { | |
fprintf( | |
stderr, | |
"Node\tT\tTnew\tdz\tkappa\tCs\tmoist\tbubble\texpt\tmax_moist\tice\n"); | |
for (i = 0; i < Nnodes; i++) { | |
fprintf( | |
stderr, | |
"%i\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\n", | |
i, T_node[i], Tnew_node[i], dz_node[i], kappa_node[i], | |
Cs_node[i], moist_node[i], bubble_node[i], expt_node[i], | |
max_moist_node[i], ice_node[i]); | |
} | |
} | |
vicerror("Finished writing calc_surf_energy_bal variables.\nTry increasing SURF_DT to get model to complete cell.\nThen check output for instabilities."); | |
return(0.0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* SUMMARY: SnowPackEnergyBalance.c - Calculate snow pack energy balance | |
* USAGE: Part of DHSVM | |
* | |
* AUTHOR: Bart Nijssen | |
* ORG: University of Washington, Department of Civil Engineering | |
* E-MAIL: nijssen@u.washington.edu | |
* ORIG-DATE: 8-Oct-1996 at 09:09:29 | |
* LAST-MOD: Thu Apr 6 12:43:30 2000 by Keith Cherkauer <cherkaue@u.washington.edu> | |
* DESCRIPTION: Calculate snow pack energy balance | |
* DESCRIP-END. | |
* FUNCTIONS: SnowPackEnergyBalance() | |
* COMMENTS: | |
*/ | |
#include <stdarg.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <vicNl.h> | |
/* RASMnote: Collect these #defines globally to ensure consistency - BN - | |
06/2012 */ | |
#define GRAMSPKG 1000. | |
/* RASMnote: Should this be 4.1868 or is this already taking into account the | |
rest of the units in the equation in which it is used? This is the same in | |
VIC 4.1.2, so I'll leave it be - BN - 06/2012 */ | |
#define CH_WATER 4186.8e3 | |
#define JOULESPCAL 4.1868 /* Joules per calorie */ | |
#define EPS 0.622 /* ratio of molecular weight of water vapor to | |
that for dry air */ | |
#define CP 1013.0 /* Specific heat of moist air at constant | |
pressure (J/(kg*C)) */ | |
/******************************************************************************* | |
Function name: SnowPackEnergyBalance() | |
Purpose : Calculate the surface energy balance for the snow pack | |
Required : | |
double TSurf - new estimate of effective surface temperature | |
va_list ap - Argument list initialized by va_start(). For | |
elements of list and order, see beginning of | |
routine | |
Returns : | |
double RestTerm - Rest term in the energy balance | |
Modifies : | |
double *RefreezeEnergy - Refreeze energy (W/m2) | |
double *VaporMassFlux - Mass flux of water vapor to or from the | |
intercepted snow (m/s) | |
Comments : | |
Reference: Bras, R. A., Hydrology, an introduction to hydrologic | |
science, Addisson Wesley, Inc., Reading, etc., 1990. | |
modifications: | |
06/2012 - code reformatting and cleanup | |
BN | |
10/2012 - ported aero_resist_used (Ra_used) from VIC 4.0.6 to store | |
the aerodynamic resistance actually used in flux | |
calculations. | |
BN | |
01/2013 - add upper limit to *Ra_used of 100 s/m under stable | |
conditions to avoid decoupling between the atmosphere and | |
the land surface. | |
BN | |
*******************************************************************************/ | |
double | |
SnowPackEnergyBalance(double TSurf, | |
va_list ap) | |
{ | |
extern option_struct options; | |
const char *Routine = "SnowPackEnergyBalance"; | |
/* start of list of arguments in variable argument list */ | |
double Dt; /* Model time step (hours) */ | |
double Ra; /* Aerodynamic resistance (s/m) */ | |
double *Ra_used; /* Aerodynamic resistance (s/m) after stability | |
correction */ | |
double Z; /* Reference height (m) */ | |
double Displacement; /* Displacement height (m) */ | |
double Z0; /* surface roughness height (m) */ | |
double Wind; /* Wind speed (m/s) */ | |
double ShortRad; /* Net incident shortwave radiation (W/m2) */ | |
double LongRadIn; /* Incoming longwave radiation (W/m2) */ | |
double AirDens; /* Density of air (kg/m3) */ | |
double Lv; /* Latent heat of vaporization (J/kg3) */ | |
double Tair; /* Air temperature (C) */ | |
double Press; /* Air pressure (Pa) */ | |
double Vpd; /* Vapor pressure deficit (Pa) */ | |
double EactAir; /* Actual vapor pressure of air (Pa) */ | |
double Rain; /* Rain fall (m/timestep) */ | |
double SweSurfaceLayer; /* Snow water equivalent in surface layer (m) | |
*/ | |
double SurfaceLiquidWater; /* Liquid water in the surface layer (m) */ | |
double OldTSurf; /* Surface temperature during previous time | |
step */ | |
double *GroundFlux; /* Ground Heat Flux (W/m2) */ | |
double *RefreezeEnergy; /* Refreeze energy (W/m2) */ | |
double *VaporMassFlux; /* Mass flux of water vapor to or from the | |
intercepted snow */ | |
double *AdvectedEnergy; /* Energy advected by precipitation (W/m2) */ | |
double *DeltaColdContent; /* Change in cold content (W/m2) */ | |
double TGrnd; | |
double SnowDepth; | |
double SnowDensity; | |
double SurfAttenuation; | |
/* end of list of arguments in variable argument list */ | |
double Density; /* Density of water/ice at TMean (kg/m3) */ | |
double EsSnow; /* saturated vapor pressure in the snow pack | |
(Pa) */ | |
double *LatentHeat; /* Latent heat exchange at surface (W/m2) */ | |
double LongRadOut; /* long wave radiation emitted by surface | |
(W/m2) */ | |
double Ls; /* Latent heat of sublimation (J/kg) */ | |
double NetRad; /* Net radiation exchange at surface (W/m2) */ | |
double RestTerm; /* Rest term in surface energy balance | |
(W/m2) */ | |
double *SensibleHeat; /* Sensible heat exchange at surface (W/m2) */ | |
double TMean; /* Average temperature for time step (C) */ | |
double Tmp; | |
/* Assign the elements of the array to the appropriate variables. The list | |
is traversed as if the elements are doubles, because: | |
In the variable-length part of variable-length argument lists, the old | |
``default argument promotions'' apply: arguments of type double are | |
always promoted (widened) to type double, and types char and short int | |
are promoted to int. Therefore, it is never correct to invoke | |
va_arg(argp, double); instead you should always use va_arg(argp, | |
double). | |
(quoted from the comp.lang.c FAQ list) | |
*/ | |
Dt = (double) va_arg(ap, double); | |
Ra = (double) va_arg(ap, double); | |
Ra_used = (double *) va_arg(ap, double *); | |
Z = (double) va_arg(ap, double); | |
Displacement = (double) va_arg(ap, double); | |
Z0 = (double) va_arg(ap, double); | |
Wind = (double) va_arg(ap, double); | |
ShortRad = (double) va_arg(ap, double); | |
LongRadIn = (double) va_arg(ap, double); | |
AirDens = (double) va_arg(ap, double); | |
Lv = (double) va_arg(ap, double); | |
Tair = (double) va_arg(ap, double); | |
Press = (double) va_arg(ap, double); | |
Vpd = (double) va_arg(ap, double); | |
EactAir = (double) va_arg(ap, double); | |
Rain = (double) va_arg(ap, double); | |
SweSurfaceLayer = (double) va_arg(ap, double); | |
SurfaceLiquidWater = (double) va_arg(ap, double); | |
OldTSurf = (double) va_arg(ap, double); | |
RefreezeEnergy = (double *) va_arg(ap, double *); | |
VaporMassFlux = (double *) va_arg(ap, double *); | |
AdvectedEnergy = (double *) va_arg(ap, double *); | |
DeltaColdContent = (double *) va_arg(ap, double *); | |
TGrnd = (double) va_arg(ap, double); | |
SnowDepth = (double) va_arg(ap, double); | |
SnowDensity = (double) va_arg(ap, double); | |
SurfAttenuation = (double) va_arg(ap, double); | |
GroundFlux = (double *) va_arg(ap, double *); | |
LatentHeat = (double *) va_arg(ap, double *); | |
SensibleHeat = (double *) va_arg(ap, double *); | |
/* Calculate active temp for energy balance as average of old and new */ | |
/* TMean = 0.5 * (OldTSurf + TSurf); */ | |
TMean = TSurf; | |
Density = RHO_W; | |
/* Correct aerodynamic conductance for stable conditions | |
Note: If air temp >> snow temp then aero_cond -> 0 (i.e. very stable) | |
velocity (vel_2m) is expected to be in m/sec */ | |
/* Apply the stability correction to the aerodynamic resistance | |
NOTE: In the old code 2m was passed instead of Z-Displacement. I (bart) | |
think that it is more correct to calculate ALL fluxes at the same | |
reference level */ | |
if (Wind > 0.0) { | |
*Ra_used = Ra / StabilityCorrection(Z, 0.f, TMean, Tair, Wind, Z0); | |
// /* RASMnote - added to avoid decoupling under stable conditions | |
// - BN - 01/2013 */ | |
// if (Tair > TMean && *Ra_used > RA_STABLE_UPPER_LIMIT) { | |
// *Ra_used = RA_STABLE_UPPER_LIMIT; | |
// } | |
} | |
else { | |
*Ra_used = HUGE_RESIST; | |
} | |
/* Calculate longwave exchange and net radiation */ | |
Tmp = TMean + KELVIN; | |
LongRadOut = EMISS * STEFAN_B * (Tmp) * (Tmp) * (Tmp) * (Tmp); | |
NetRad = SurfAttenuation * ShortRad + (EMISS * LongRadIn) - LongRadOut; | |
/* Calculate the sensible heat flux */ | |
*SensibleHeat = AirDens * CP * (Tair - TMean) / *Ra_used; | |
/* Calculate the mass flux of ice to or from the surface layer */ | |
/* Calculate the saturated vapor pressure in the snow pack */ | |
EsSnow = svp(TMean) * 1000.; | |
*VaporMassFlux = AirDens * (EPS / Press) * (EactAir - EsSnow) / *Ra_used; | |
*VaporMassFlux /= Density; | |
if (Vpd == 0.0 && *VaporMassFlux < 0.0) { | |
*VaporMassFlux = 0.0; | |
} | |
/* Calculate latent heat flux */ | |
if (TMean >= 0.0) { | |
/* Melt conditions: use latent heat of vaporization */ | |
*LatentHeat = Lv * *VaporMassFlux * Density; | |
} | |
else { | |
/* Accumulation: use latent heat of sublimation (Eq. 3.19, Bras 1990 */ | |
Ls = (677. - 0.07 * TMean) * JOULESPCAL * GRAMSPKG; | |
*LatentHeat = Ls * *VaporMassFlux * Density; | |
} | |
/* Calculate advected heat flux from rain | |
WORK IN PROGRESS: Should the following read (Tair - Tsurf) ?? */ | |
*AdvectedEnergy = (CH_WATER * Tair * Rain) / (Dt * SECPHOUR); | |
/* Calculate change in cold content */ | |
*DeltaColdContent = CH_ICE * SweSurfaceLayer * (TSurf - OldTSurf) / | |
(Dt * SECPHOUR); | |
/* Calculate Ground Heat Flux */ | |
if (SnowDepth > 0.) { | |
*GroundFlux = 2.9302e-6 * SnowDensity * SnowDensity * | |
(TGrnd - TMean) / SnowDepth; | |
} | |
else { | |
*GroundFlux = 0; | |
} | |
*DeltaColdContent -= *GroundFlux; | |
/* Calculate net energy exchange at the snow surface */ | |
RestTerm = NetRad + *SensibleHeat + *LatentHeat + *AdvectedEnergy - | |
*DeltaColdContent; | |
*RefreezeEnergy = (SurfaceLiquidWater * Lf * Density) / (Dt * SECPHOUR); | |
if (TSurf == 0.0 && RestTerm > -(*RefreezeEnergy)) { | |
*RefreezeEnergy = -RestTerm; /* available energy input over cold content | |
used to melt, i.e. Qrf is negative value | |
(energy out of pack)*/ | |
RestTerm = 0.0; | |
} | |
else { | |
RestTerm += *RefreezeEnergy; /* add this positive value to the pack */ | |
} | |
return RestTerm; | |
} | |
#undef GRAMSPKG | |
#undef CH_WATER | |
#undef JOULESPCAL | |
#undef EPS | |
#undef CP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment