/***************************************************************************** Function name: IceEnergyBalance() Purpose : Calculate the surface energy balance for the snow pack Required : double TSurf - new estimate of effective surface temperature 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: 16-Jul-04 Renamed VaporMassFlux to vapor_flux to denote fact that its units are m/timestep rather than kg/m2s. Created new variable VaporMassFlux with units of kg/m2s. After VaporMassFlux is computed, vapor_flux is derived from it by unit conversion. vapor_flux is the variable that is passed in/out of this function. TJB 24-Aug-04 Added logic to handle blowing_flux and vapor_flux. TJB 28-Sep-04 Added Ra_used to store the aerodynamic resistance used in flux calculations. TJB 04-Oct-04 Merged with Laura Bowling's updated lake model code. Now blowing snow sublimation is calculated for lakes. TJB 2006-Sep-23 Replaced redundant STEFAN constant with STEFAN_B. TJB 2006-Nov-07 Removed LAKE_MODEL option. TJB *****************************************************************************/ double IceEnergyBalance::calculate(double TSurf) { const char *Routine = "IceEnergyBalance"; double Density; /* Density of water/ice at TMean (kg/m3) */ double EsSnow; /* saturated vapor pressure in the snow pack (Pa) */ 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 TMean; /* Average temperature for time step (C) */ double qnull; double VaporMassFlux; /* Total mass flux of water vapor to or from snow (kg/m2s) */ double BlowingMassFlux; /* Mass flux of water vapor to or from blowing snow (kg/m2s) */ double SurfaceMassFlux; /* Mass flux of water vapor to or from snow pack (kg/m2s) */ /* 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); /* *Ra_used = Ra / StabilityCorrection(2.f, 0.f, TMean, Tair, Wind, Z0);*/ else *Ra_used = HUGE_RESIST; /* Calculate longwave exchange and net radiation */ *LongRadOut = LongRadIn - STEFAN_B * (TMean+273.15) * (TMean+273.15) * (TMean+273.15) * (TMean+273.15); NetRad = ShortRad + *LongRadOut; /* Calculate the sensible heat flux */ *SensibleHeat = AirDens * CP_PM * (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, (Equation 3.32, Bras 1990) */ EsSnow = svp(TMean) /* * 1000. */; /* EsSnow = 610.78 * exp((double)((17.269 * TMean) / (237.3 + TMean))); */ /* if (TMean < 0.0) */ /* EsSnow *= 1.0 + .00972 * TMean + .000042 * pow((double)TMean,(double)2.0); */ /* Calculate sublimation terms and latent heat flux */ /* blowing_flux was calculated outside of the root_brent iteration */ BlowingMassFlux = *blowing_flux * Density / (Dt * SECPHOUR); latent_heat_from_snow(AirDens, EactAir, Lv, Press, Ra, TMean, Vpd, LatentHeat, LatentHeatSub, &VaporMassFlux, &BlowingMassFlux, &SurfaceMassFlux); /* Convert sublimation terms from kg/m2s to m/timestep */ *vapor_flux = VaporMassFlux * Dt * SECPHOUR / Density; *surface_flux = SurfaceMassFlux * Dt * SECPHOUR / Density; /* Calculate advected heat flux from rain WORK IN PROGRESS: Should the following read (Tair - Tsurf) ?? */ // Temporary fix for lake model. *AdvectedEnergy = (CH_WATER * Tair * Rain) / (Dt*SECPHOUR); //*AdvectedEnergy = 0.0; /* Calculate change in cold content */ /* No change in cold content in lake model */ /* Changes for lake model start here. Actually, equals qo-Io (P&H eq. 7)*/ /* because Io (SWnet) is included in NetRad below. */ qnull = (1/AvgCond)*(Tfreeze - TMean + SWconducted); *qf = qnull; /* Changes for lake model end here. */ /* Calculate net energy exchange at the snow surface */ RestTerm = ( NetRad + *SensibleHeat + *LatentHeat + *LatentHeatSub + *AdvectedEnergy + qnull ); *RefreezeEnergy = (SurfaceLiquidWater * Lf * Density)/(Dt * SECPHOUR); /* Melting, or partially refreeze surface water. */ 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 { /* Pack is getting colder. */ RestTerm += *RefreezeEnergy; /* add this positive value to the pack */ } return RestTerm; }
void CSensibleHeatFlux::init(int y, int x, int Dt, float Ra, float ZRef, float Displacement, float Z0, PIXMET * LocalMet, float NetShort, float LongIn, float ETot, int NSoilLayers, float *SoilDepth, SOILTABLE * SoilType, float MeltEnergy, SOILPIX * LocalSoil) { float FluxDepth; /* Lower boundary for soil heat flux (m) */ float HeatCapacity; /* Soil heat capacity */ float MaxTSurf; /* Upper bracket for effective surface temperature (C) */ float MinTSurf; /* Lower bracket for effective surface temperature (C) */ float OldTSurf; /* Effective surface temperature at the end of the last timestep (C) */ float KhEff; /* Thermal conductivity of the soil (W/(m*C) */ float TMean; /* Average surface temperature (C) */ float TSoilLower; /* Temperature os the soil at FluxDepth (C) */ float TSoilUpper; /* Temperature os the soil in top layer (C) */ double Tmp; /* Temporary value */ OldTSurf = LocalSoil->TSurf; MaxTSurf = 0.5 * (LocalSoil->TSurf + LocalMet->Tair) + DELTAT; MinTSurf = 0.5 * (LocalSoil->TSurf + LocalMet->Tair) - DELTAT; /* WORK IN PROGRESS */ /* the lower boundary for the soil heat flux is currently fixed at a depth of 1.0 m */ FluxDepth = 1.0; TSoilLower = LocalSoil->Temp[NSoilLayers - 1]; TSoilUpper = LocalSoil->Temp[0]; /* Calculate the effective thermal conductivity of the soil above between FluxDepth and DZ_TOP */ KhEff = CalcEffectiveKh(NSoilLayers, DZ_TOP, FluxDepth, SoilDepth, SoilType->KhDry, SoilType->KhSol, LocalSoil->Moist, SoilType->Porosity, LocalSoil->Temp); /* KhEff = 1; */ /* Calculate the effective surface temperature that makes sure that the sum of the terms of the energy balance equals 0 */ LocalSoil->TSurf = RootBrent(y, x, MinTSurf, MaxTSurf, SurfaceEnergyBalance, Dt, Ra, ZRef, Displacement, Z0, LocalMet->Wind, NetShort, LongIn, LocalMet->AirDens, LocalMet->Lv, ETot, KhEff, SoilType->Ch[0], SoilType->Porosity[0], LocalSoil->Moist[0], FluxDepth, LocalMet->Tair, TSoilUpper, TSoilLower, OldTSurf, MeltEnergy); /* Calculate the terms of the energy balance. This is similar to the code in SurfaceEnergyBalance.c */ TMean = 0.5 * (OldTSurf + LocalSoil->TSurf); if (LocalMet->Wind > 0.0) Ra /= StabilityCorrection(ZRef, Displacement, TMean, LocalMet->Tair, LocalMet->Wind, Z0); else Ra = DHSVM_HUGE; LocalSoil->Ra = Ra; Tmp = TMean + 273.15; LocalSoil->Qnet = NetShort + LongIn - STEFAN * (Tmp * Tmp * Tmp * Tmp); LocalSoil->Qs = LocalMet->AirDens * CP * (LocalMet->Tair - TMean) / Ra; LocalSoil->Qe = -(LocalMet->Lv * ETot) / Dt * WATER_DENSITY; LocalSoil->Qg = KhEff * (TSoilLower - TMean) / FluxDepth; HeatCapacity = (1 - SoilType->Porosity[0]) * SoilType->Ch[0]; if (TSoilUpper >= 0.0) HeatCapacity += LocalSoil->Moist[0] * CH_WATER; else HeatCapacity += LocalSoil->Moist[0] * CH_ICE; LocalSoil->Qst = (HeatCapacity * (OldTSurf - TMean) * DZ_TOP) / Dt; LocalSoil->Qrest = LocalSoil->Qnet + LocalSoil->Qs + LocalSoil->Qe + LocalSoil->Qg + LocalSoil->Qst + MeltEnergy; }