/****************************************************************************** * @brief Calculate sublimation from blowing snow *****************************************************************************/ double CalcBlowingSnow(double Dt, double Tair, unsigned LastSnow, double SurfaceLiquidWater, double Wind, double Ls, double AirDens, double EactAir, double ZO, double Zrh, double snowdepth, double lag_one, double sigma_slope, double Tsnow, int iveg, int Nveg, double fe, double displacement, double roughness, double *TotalTransport) { extern parameters_struct param; extern option_struct options; /* Local variables: */ double Age; double U10, Uo, prob_occurence; double es, Ros, F; double SubFlux; double Diffusivity; double ushear; double Tk; double utshear; int p; double upper, lower, Total; double area; double sigma_w; double Zo_salt; double ratio, wind10; double Uveg, hv, Nd; double Transport; /*******************************************************************/ /* Calculate some general variables, that don't depend on wind speed. */ /* Age in hours */ Age = LastSnow * Dt / SEC_PER_HOUR; /* Saturation density of water vapor, Liston A-8 */ es = svp(Tair); Tk = Tair + CONST_TKFRZ; Ros = CONST_EPS * es / (CONST_RDAIR * Tk); /* Diffusivity in m2/s, Liston eq. A-7 */ Diffusivity = (2.06e-5) * pow(Tk / 273., 1.75); // Essery et al. 1999, eq. 6 (m*s/kg) F = (Ls / (param.BLOWING_KA * Tk)) * (Ls * Tk / CONST_RDAIR - 1.); F += 1. / (Diffusivity * Ros); /* grid cell 10 m wind speed = 50th percentile wind */ /* Wind speed at 2 m above snow was passed to this function. */ wind10 = Wind * log(10. / ZO) / log((2 + ZO) / ZO); /* Check for bare soil case. */ if (iveg == Nveg) { fe = 1500; sigma_slope = .0002; } // sigma_w/uo: ratio = (2.44 - (0.43) * lag_one) * sigma_slope; sigma_w = wind10 * ratio; Uo = wind10; /*********** Parameters for roughness above snow. *****************/ hv = (3. / 2.) * displacement; Nd = (4. / 3.) * (roughness / displacement); /*******************************************************************/ /** Begin loop through wind probability function. */ Total = 0.0; *TotalTransport = 0.0; area = 1. / (double) param.BLOWING_NUMINCS; if (snowdepth > 0.0) { if (options.BLOWING_SPATIAL_WIND && sigma_w != 0.) { for (p = 0; p < param.BLOWING_NUMINCS; p++) { SubFlux = lower = upper = 0.0; /* Find the limits of integration. */ if (p == 0) { lower = -9999; upper = Uo + sigma_w * log(2. * (p + 1) * area); } else if (p > 0 && p < param.BLOWING_NUMINCS / 2) { lower = Uo + sigma_w * log(2. * (p) * area); upper = Uo + sigma_w * log(2. * (p + 1) * area); } else if (p < (param.BLOWING_NUMINCS - 1) && p >= (double) param.BLOWING_NUMINCS / 2) { lower = Uo - sigma_w * log(2. - 2. * (p * area)); upper = Uo - sigma_w * log(2. - 2. * ((p + 1.) * area)); } else if (p == param.BLOWING_NUMINCS - 1) { lower = Uo - sigma_w * log(2. - 2. * (p * area)); upper = 9999; } if (lower > upper) { /* Could happen if lower > Uo*2 */ lower = upper; log_err("Error with probability boundaries"); } /* Find expected value of wind speed for the interval. */ U10 = Uo; if (lower >= Uo) { U10 = -0.5 * ((upper + sigma_w) * exp((-1. / sigma_w) * (upper - Uo)) - (lower + sigma_w) * exp((-1. / sigma_w) * (lower - Uo))) / area; } else if (upper <= Uo) { U10 = 0.5 * ((upper - sigma_w) * exp((1. / sigma_w) * (upper - Uo)) - (lower - sigma_w) * exp((1. / sigma_w) * (lower - Uo))) / area; } else { log_err("Problem with probability ranges: Increment = %d, " "integration limits = %f - %f", p, upper, lower); } if (U10 < 0.4) { U10 = .4; } if (U10 > 25.) { U10 = 25.; } /*******************************************************************/ /* Calculate parameters for probability of blowing snow occurence. */ /* ( Li and Pomeroy 1997) */ if (snowdepth < hv) { Uveg = U10 / sqrt(1. + 170 * Nd * (hv - snowdepth)); } else { Uveg = U10; } prob_occurence = get_prob(Tair, Age, SurfaceLiquidWater, Uveg); /*******************************************************************/ /* Calculate threshold shear stress. Send 0 for constant or */ /* 1 for variable threshold after Li and Pomeroy (1997) */ utshear = get_thresh(Tair, SurfaceLiquidWater, ZO); /* Iterate to find actual shear stress during saltation. */ shear_stress(U10, ZO, &ushear, &Zo_salt, utshear); if (ushear > utshear) { SubFlux = CalcSubFlux(EactAir, es, Zrh, AirDens, utshear, ushear, fe, Tsnow, Tair, U10, Zo_salt, F, &Transport); } else { SubFlux = 0.0; Transport = 0.0; } Total += (1. / (double) param.BLOWING_NUMINCS) * SubFlux * prob_occurence; *TotalTransport += (1. / (double) param.BLOWING_NUMINCS) * Transport * prob_occurence; } } else { U10 = Uo; /*******************************************************************/ /* Calculate parameters for probability of blowing snow occurence. */ /* ( Li and Pomeroy 1997) */ if (snowdepth < hv) { Uveg = U10 / sqrt(1. + 170 * Nd * (hv - snowdepth)); } else { Uveg = U10; } prob_occurence = get_prob(Tair, Age, SurfaceLiquidWater, Uveg); /*******************************************************************/ /* Calculate threshold shear stress. Send 0 for constant or */ /* 1 for variable threshold after Li and Pomeroy (1997) */ utshear = get_thresh(Tair, SurfaceLiquidWater, ZO); /* Iterate to find actual shear stress during saltation. */ shear_stress(Uo, ZO, &ushear, &Zo_salt, utshear); if (ushear > utshear) { SubFlux = CalcSubFlux(EactAir, es, Zrh, AirDens, utshear, ushear, fe, Tsnow, Tair, Uo, Zo_salt, F, &Transport); } else { SubFlux = 0.0; Transport = 0.0; } Total = SubFlux * prob_occurence; *TotalTransport = Transport * prob_occurence; } } if (Total < -.00005) { Total = -.00005; } return Total; }
/***************************************************************************** Function name: CalcBlowingSnow() Purpose : Calculate sublimation from blowing snow Required : double Dt; Model time step (hours) double Tair; Air temperature (C) int LastSnow; Time steps since last snowfall. double SurfaceLiquidWater; Liquid water in the surface layer (m) double Wind; Wind speed (m/s), 2 m above snow double Ls; Latent heat of sublimation (J/kg) double AirDens; Density of air (kg/m3) double Lv; Latent heat of vaporization (J/kg3) double Press; Air pressure (Pa) double EactAir; Actual vapor pressure of air (Pa) double ZO; Snow roughness height (m) Returns : BlowingMassFlux Modifies : Comments : Called from SnowPackEnergyBalance Reference: *****************************************************************************/ double CalcBlowingSnow( double Dt, double Tair, int LastSnow, double SurfaceLiquidWater, double Wind, double Ls, double AirDens, double Press, double EactAir, double ZO, double Zrh, double snowdepth, float lag_one, float sigma_slope, double Tsnow, int iveg, int Nveg, float fe, double displacement, double roughness, double *TotalTransport) { /* Local variables: */ double Age; double U10, Uo, prob_occurence; double es, Ros, F; double SubFlux; double Diffusivity; double ushear, Qsalt, hsalt, phi_s, psi_s; double Tk; double Lv; double T, ztop; double ut10, utshear; int p; double upper, lower, Total; double area; double sigma_w; double undersat_2; double b, temp2; /* SBSM scaling parameter. */ double temp, temp3; double Zo_salt; double ratio, wind10; double Uveg, hv, Nd; double Transport; int count=0; Lv = (2.501e6 - 0.002361e6 * Tsnow); /*******************************************************************/ /* Calculate some general variables, that don't depend on wind speed. */ /* Age in hours */ Age = LastSnow*(Dt); /* Saturation density of water vapor, Liston A-8 */ es = svp(Tair); Tk = Tair + KELVIN; Ros = 0.622*es/(287*Tk); /* Diffusivity in m2/s, Liston eq. A-7 */ Diffusivity = (2.06e-5) * pow(Tk/273.,1.75); // Essery et al. 1999, eq. 6 (m*s/kg) F = (Ls/(Ka*Tk))*(Ls*MW/(R*Tk) - 1.); F += 1./(Diffusivity*Ros); /* grid cell 10 m wind speed = 50th percentile wind */ /* Wind speed at 2 m above snow was passed to this function. */ wind10 = Wind*log(10./ZO)/log((2+ZO)/ZO); // fprintf(stderr,"wind=%f, Uo=%f\n",Wind, Uo); /* Check for bare soil case. */ if(iveg == Nveg) { fe = 1500; sigma_slope = .0002; } // sigma_w/uo: ratio = (2.44 - (0.43)*lag_one)*sigma_slope; // sigma_w = wind10/(.69+(1/ratio)); // Uo = sigma_w/ratio; sigma_w = wind10*ratio; Uo = wind10; /*********** Parameters for roughness above snow. *****************/ hv = (3./2.)*displacement; Nd = (4./3.)*(roughness/displacement); /*******************************************************************/ /** Begin loop through wind probability function. */ Total = 0.0; *TotalTransport = 0.0; area = 1./NUMINCS; if(snowdepth > 0.0) { if(SPATIAL_WIND && sigma_w != 0.) { for(p= 0; p< NUMINCS; p++) { SubFlux = lower = upper = 0.0; /* Find the limits of integration. */ if(p==0) { lower = -9999; upper = Uo + sigma_w*log(2.*(p+1)*area); } else if(p > 0 && p < NUMINCS/2) { lower = Uo + sigma_w*log(2.*(p)*area); upper = Uo + sigma_w*log(2.*(p+1)*area); } else if(p < (NUMINCS-1) && p >= NUMINCS/2) { lower = Uo - sigma_w*log(2.-2.*(p*area)); upper = Uo - sigma_w*log(2.-2.*((p+1.)*area)); } else if(p == NUMINCS-1) { lower = Uo - sigma_w*log(2.-2.*(p*area)); upper = 9999; } if(lower > upper) {/* Could happen if lower > Uo*2 */ lower = upper; fprintf(stderr,"Warning: Error with probability boundaries in CalcBlowingSnow()\n"); } /* Find expected value of wind speed for the interval. */ U10 = Uo; if(lower >= Uo ) U10 = -0.5*((upper+sigma_w)*exp((-1./sigma_w)*(upper - Uo)) - (lower+sigma_w)*exp((-1./sigma_w)*(lower - Uo)))/area; else if(upper <= Uo ) U10 = 0.5*((upper-sigma_w)*exp((1./sigma_w)*(upper - Uo)) - (lower-sigma_w)*exp((1./sigma_w)*(lower - Uo)))/area; else { fprintf(stderr,"ERROR in CalcBlowingSnow.c: Problem with probability ranges\n"); fprintf(stderr," Increment = %d, integration limits = %f - %f\n",p,upper, lower); return ( ERROR ); } if(U10 < 0.4) U10 = .4; if(U10 > 25.) U10 = 25.; /*******************************************************************/ /* Calculate parameters for probability of blowing snow occurence. */ /* ( Li and Pomeroy 1997) */ if(snowdepth < hv) { Uveg = U10/sqrt(1.+ 170*Nd*(hv - snowdepth)); } else Uveg = U10; // fprintf(stderr, "Uveg = %f, U10 = %f\n",Uveg, U10); prob_occurence = get_prob(Tair, Age, SurfaceLiquidWater, Uveg); // printf("prob=%f\n",prob_occurence); /*******************************************************************/ /* Calculate threshold shear stress. Send 0 for constant or */ /* 1 for variable threshold after Li and Pomeroy (1997) */ utshear = get_thresh(Tair, SurfaceLiquidWater, ZO, VAR_THRESHOLD); /* Iterate to find actual shear stress during saltation. */ shear_stress(U10, ZO, &ushear, &Zo_salt, utshear); if(ushear > utshear) { SubFlux = CalcSubFlux(EactAir, es, Zrh, AirDens, utshear,ushear, fe, Tsnow, Tair, U10, Zo_salt, F, &Transport); } else { SubFlux=0.0; Transport = 0.0; } Total += (1./NUMINCS)*SubFlux*prob_occurence; *TotalTransport += (1./NUMINCS)*Transport*prob_occurence; } } else { U10=Uo; /*******************************************************************/ /* Calculate parameters for probability of blowing snow occurence. */ /* ( Li and Pomeroy 1997) */ if(snowdepth < hv) Uveg = U10/sqrt(1.+ 170*Nd*(hv - snowdepth)); else Uveg = U10; prob_occurence = get_prob(Tair, Age, SurfaceLiquidWater, Uveg); /*******************************************************************/ /* Calculate threshold shear stress. Send 0 for constant or */ /* 1 for variable threshold after Li and Pomeroy (1997) */ utshear = get_thresh(Tair, SurfaceLiquidWater, ZO, VAR_THRESHOLD); /* Iterate to find actual shear stress during saltation. */ shear_stress(Uo, ZO, &ushear, &Zo_salt, utshear); if(ushear > utshear) { SubFlux = CalcSubFlux(EactAir, es, Zrh, AirDens, utshear,ushear, fe, Tsnow, Tair, Uo, Zo_salt, F, &Transport); } else { SubFlux=0.0; Transport = 0.0; } Total = SubFlux*prob_occurence; *TotalTransport = Transport*prob_occurence; } } if(Total < -.00005) Total = -.00005; return Total; }