예제 #1
0
int surface_fluxes(char                 overstory,
		   double               BareAlbedo,
		   double               height,
		   double               ice0,
		   double               moist0,
#if EXCESS_ICE
		   int                  SubsidenceUpdate,
		   double              *evap_prior_dry,
		   double              *evap_prior_wet,
#endif
		   double               mu,
		   double               surf_atten,
		   double              *Melt,
		   double              *Le,
		   double             **aero_resist,
		   double              *displacement,
		   double              *gauge_correction,
		   double              *out_prec,
		   double              *out_rain,
		   double              *out_snow,
		   double              *ref_height,
		   double              *roughness,
		   double              *snow_inflow,
		   double              *wind,
		   float               *root,
		   int                  Nbands,
		   int                  Ndist,
		   int                  Nlayers,
		   int                  Nveg,
		   int                  band,
		   int                  dp,
		   int                  iveg,
		   int                  rec,
		   int                  veg_class,
		   atmos_data_struct   *atmos,
		   dmy_struct          *dmy,
		   energy_bal_struct   *energy,
		   global_param_struct *gp,
		   cell_data_struct    *cell_dry,
		   cell_data_struct    *cell_wet,
		   snow_data_struct    *snow,
		   soil_con_struct     *soil_con,
		   veg_var_struct      *veg_var_dry,
		   veg_var_struct      *veg_var_wet,
		   float              lag_one,
		   float              sigma_slope,
		   float              fetch)
/**********************************************************************
	surface_fluxes	Keith Cherkauer		February 29, 2000

  Formerly a part of full_energy.c this routine computes all surface
  fluxes, and solves the snow accumulation and ablation algorithm.
  Solutions are for the current snow band and vegetation type (these
  are defined in full_energy before the routine is called).

  modifications:
  10-06-00 modified to handle partial snow cover                KAC
  10-31-00 modified to iterate a solution for the exchange of
           energy between the snowpack and the ground surface.  KAC
  11-18-02 modified to add the effects of blowing snow.         LCB
  02-07-03 fixed indexing problem for sub-daily snow model within
           daily water balance VIC: hour (now hidx) is incremented
           by 1 rather than the sub-daily time step, so the atmospheric
           forcing data is now properly indexed.                KAC
  04-23-03 Indexing fix sent SNOW_STEP to calc_surf_energy_bal rather
           than the model time step, meaning that without snow the 
           evaporation was computed for SNOW_STEP hours rather than a
           full day.  This was fixed by introducing step_inc to 
           index the arrays, while step_dt keeps track of the correct
           time step.                                          		KAC
  10-May-04 Fixed initialization of canopyevap to initialize for every
	    value of dist, rather than just dist 0.			TJB
  16-Jul-04 Added variables store_blowing_flux and store_surface_flux
	    so that surface_flux and blowing_flux are calculated
	    correctly over a model time step.				TJB
  16-Jul-04 Moved calculation of blowing_flux from this function
	    into latent_heat_from_snow().				TJB
  05-Aug-04 Moved calculation of blowing_flux back into this function
	    from latent_heat_from_snow().  Updated arg lists to
	    calc_surf_energy_bal() and solve_snow() accordingly.	TJB
  28-Sep-04 Added aero_resist_used to store the aerodynamic resistance
	    used in flux calculations.					TJB
  04-Oct-04 Merged with Laura Bowling's updated lake model code.	TJB
  2006-Sep-23 Implemented flexible output configuration; moved tracking
              of rain and snow for output to this function.		TJB
  2006-Sep-26 Moved tracking of out_rain and out_snow to solve_snow.c.	TJB
  2006-Dec-20 Modified iteration loop variables to be more intuitive.	TJB
  2007-Apr-04 Modified to handle grid cell errors by returning to the
	      main subroutine, rather than ending the simulation.	GCT/KAC
  24-Apr-07 Features included for IMPLICIT frozen soils option.		JCA
	    (passing nrecs to  calc_surf_energy_bal)
  2007-Jul-03 Added iter_snow, iter_bare_energy, and iter_snow_energy
	      structures so that canopy/understory iterations don't
	      reset step_snow, etc.  This fixes a bug involving large
	      water balance errors when model step = daily and snow
	      step = sub-daily.						TJB
  2007-Aug-17 Added features for EXCESS_ICE option.                     JCA
  2008-May-05 Changed moist from a scalar to an array (moist0).  Previously,
	      when options.SNOW_BAND > 1, the value of moist computed
	      for earlier bands was always overwritten by the value
	      of moist computed for the final band (even if the final
	      band had 0 area).						KAC via TJB
  2008-Oct-23 In call to CalcBlowing(), replaced
	        veg_lib[iveg].displacement[dmy[rec].month-1] and
	        veg_lib[iveg].roughness[dmy[rec].month-1] with
	      *displacement and *roughness.				LCB via TJB
  2009-Jan-16 Modified aero_resist_used and Ra_used to become arrays of
	      two elements (surface and overstory); added
	      options.AERO_RESIST_CANSNOW.				TJB
  2009-May-17 Added asat to cell_data.					TJB
  2009-May-20 Changed "bare_*" to "soil_*", to make it clearer that
	      these data structures refer to the energy balance at the
	      soil surface, regardless of whether the surface is covered
	      by snow or some veg or is totally bare.			TJB
  2009-Jun-09 Modified to use extension of veg_lib structure to contain
	      bare soil information.					TJB
  2009-Jun-09 Added call to compute_pot_evap() to compute potential
	      evaporation for various land cover types.			TJB
  2009-Jun-09 Cell_data structure now only stores final aero_resist
	      values (called "aero_resist").  Preliminary uncorrected
	      aerodynamic resistances for current vegetation and various
	      reference land cover types for use in potential evap
	      calculations is stored in temporary array aero_resist.	TJB
  2009-Jun-19 Added T flag to indicate whether TFALLBACK occurred.	TJB
  2009-Jun-26 Simplified argument list of runoff() by passing all cell_data
	      variables via a single reference to the cell data structure.	TJB
  2009-Sep-19 Added T fbcount to count TFALLBACK occurrences.		TJB
  2009-Nov-15 Removed ice0 and moist0 from argument list of solve_snow,
	      since they are never used.				TJB
  2010-Apr-24 Added logic to handle case when aero_cond or aero_resist
	      are very large or 0.					TJB
  2010-Apr-26 Simplified argument lists for solve_snow() and
	      snow_intercept().						TJB
  2011-May-31 Removed options.GRND_FLUX.				TJB
  2012-Jan-16 Removed LINK_DEBUG code					BN
**********************************************************************/
{
  extern veg_lib_struct *veg_lib;
  extern option_struct   options;
  double                 total_store_moist[3];
  double                 step_store_moist[3];

  int                    BISECT_OVER;
  int                    BISECT_UNDER;
  int                    ErrorFlag;
  int                    INCLUDE_SNOW = FALSE;
  int                    UNSTABLE_CNT;
  int                    UNSTABLE_SNOW = FALSE;
  int                    N_steps;
  int                    UnderStory;
  int                    dist;
  int                    hidx;     // index of initial element of atmos array
  int                    step_inc; // number of atmos array elements to skip per surface fluxes step
  int                    endhidx;  // index of final element of atmos array
  int                    step_dt;  // time length of surface fluxes step
  int                    lidx;
  int                    over_iter;
  int                    under_iter;
  int                    p,q;
  double                 Evap;
  double                 Ls;
  double                 LongUnderIn; // inmoing LW to ground surface
  double                 LongUnderOut; // outgoing LW from ground surface
  double                 NetLongSnow; // net LW over snowpack
  double                 NetShortSnow; // net SW over understory
  double                 NetShortGrnd; // net SW over snow-free surface
  double                 OldTSurf; // previous snow surface temperature
  double                 ShortUnderIn; // incoming SW to understory
  double                 Tair; // air temperature
  double                 Tcanopy; // canopy air temperature
  double                 Tgrnd; // soil surface temperature
  double                 Tsurf; // ground surface temperature
  double                 VPDcanopy; // vapor pressure deficit in canopy/atmos
  double                 VPcanopy; // vapor pressure in canopy/atmos
  double                 coverage; // mid-step snow cover fraction
  double                 delta_coverage; // change in snow cover fraction
  double                 delta_snow_heat; // change in snowpack heat storage
  double                 last_Tcanopy;
  double                 last_Tgrnd;
  double                 last_Tsurf;
  double                 last_latent_ground_heat;
  double                 last_snow_coverage; // previous snow covered area
  double                 last_snow_flux;
  double                 last_tol_under; // previous surface iteration tol
  double                 last_tol_over; // previous overstory iteration tol
  double                 latent_ground_heat; // latent heat from understory
  double                 ppt[2]; // precipitation/melt reaching soil surface
  double                 rainfall[2]; // rainfall
  double                 snowfall[2]; // snowfall
  double                 snow_flux; // heat flux through snowpack
  double                 snow_grnd_flux; // ground heat flux into snowpack
  double                 tol_under;
  double                 tol_over;
  double                *aero_resist_used;
  double                *baseflow_dry;
  double                *baseflow_wet;
  double                *asat_dry;
  double                *asat_wet;
  double                *pot_evap;
  double                *inflow_dry;
  double                *inflow_wet;
  double                *runoff_dry;
  double                *runoff_wet;
  layer_data_struct     *layer_dry;
  layer_data_struct     *layer_wet;

  // Step-specific quantities
  double                 step_Evap;
  double                 step_Wdew[2];
  double                 step_melt;
  double                 step_melt_energy;  /* energy used to reduce snow coverage */
  double                 step_out_prec;
  double                 step_out_rain;
  double                 step_out_snow;
  double                 step_ppt[2];
  double                 step_prec[2];
  double               **step_aero_resist;

  // Quantities that need to be summed or averaged over multiple snow steps
  // energy structure
  double                 store_AlbedoOver;
  double                 store_AlbedoUnder;
  double                 store_AtmosLatent;
  double                 store_AtmosLatentSub;
  double                 store_AtmosSensible;
  double                 store_LongOverIn;
  double                 store_LongUnderIn;
  double                 store_LongUnderOut;
  double                 store_NetLongAtmos;
  double                 store_NetLongOver;
  double                 store_NetLongUnder;
  double                 store_NetShortAtmos;
  double                 store_NetShortGrnd;
  double                 store_NetShortOver;
  double                 store_NetShortUnder;
  double                 store_ShortOverIn;
  double                 store_ShortUnderIn;
  double                 store_advected_sensible;
  double                 store_advection; 
  double                 store_canopy_advection;
  double                 store_canopy_latent;
  double                 store_canopy_latent_sub;
  double                 store_canopy_sensible;
  double                 store_canopy_refreeze;
  double                 store_deltaCC; 
  double                 store_deltaH;
  double                 store_fusion;
  double                 store_grnd_flux;
  double                 store_latent;
  double                 store_latent_sub;
  double                 store_melt_energy;
  double                 store_refreeze_energy; 
  double                 store_sensible;
  double                 store_snow_flux; 
  // snow structure
  double                 store_canopy_vapor_flux;
  double                 store_melt;
  double                 store_vapor_flux;
  double                 store_blowing_flux;
  double                 store_surface_flux;
  // veg_var structure
  double                 store_canopyevap[2];
  double                 store_throughfall[2];
  // cell structure
  double                 store_layerevap[2][MAX_LAYERS];
  double                 store_ppt[2];
  double                 store_aero_cond_used[2];
  double                 store_pot_evap[N_PET_TYPES];

  // Structures holding values for current snow step
  energy_bal_struct      snow_energy; // energy fluxes at snowpack surface
  energy_bal_struct      soil_energy; // energy fluxes at soil surface
  veg_var_struct         snow_veg_var[2]; // veg fluxes/storages in presence of snow
  veg_var_struct         soil_veg_var[2]; // veg fluxes/storages in soil energy balance
  snow_data_struct       step_snow;
  layer_data_struct      step_layer[2][MAX_LAYERS];

  // Structures holding values for current iteration
  energy_bal_struct      iter_snow_energy; // energy fluxes at snowpack surface
  energy_bal_struct      iter_soil_energy; // energy fluxes at soil surface
  veg_var_struct         iter_snow_veg_var[2]; // veg fluxes/storages in presence of snow
  veg_var_struct         iter_soil_veg_var[2]; // veg fluxes/storages in soil energy balance
  snow_data_struct       iter_snow;
  layer_data_struct      iter_layer[2][MAX_LAYERS];
  double                 iter_aero_resist[3];
  double                 iter_aero_resist_used[2];
  double                 stability_factor[2];
  double                 iter_pot_evap[N_PET_TYPES];

  // handle bisection of understory solution
  double store_tol_under;
  double A_tol_under;
  double B_tol_under;
  double A_snow_flux;
  double B_snow_flux;

  // handle bisection of overstory solution
  double store_tol_over;
  double A_tol_over;
  double B_tol_over;
  double A_Tcanopy;
  double B_Tcanopy;

  /***********************************************************************
    Set temporary variables for convenience
  ***********************************************************************/
  aero_resist_used = cell_wet->aero_resist;
  baseflow_dry = &(cell_dry->baseflow);
  baseflow_wet = &(cell_wet->baseflow);
  asat_dry = &(cell_dry->asat);
  asat_wet = &(cell_wet->asat);
  pot_evap = cell_wet->pot_evap;
  inflow_dry = &(cell_dry->inflow);
  inflow_wet = &(cell_wet->inflow);
  runoff_dry = &(cell_dry->runoff);
  runoff_wet = &(cell_wet->runoff);
  layer_dry = cell_dry->layer;
  layer_wet = cell_wet->layer;

  step_aero_resist = (double**)calloc(N_PET_TYPES,sizeof(double*));
  for (p=0; p<N_PET_TYPES; p++) {
    step_aero_resist[p] = (double*)calloc(2,sizeof(double));
  }

  /***********************************************************************
    Set temporary variables - preserves original values until iterations
    are completed
  ***********************************************************************/

  energy->advection       = 0; 
  energy->deltaCC         = 0; 
  if ( snow->swq > 0 ) {
      snow_flux = energy->snow_flux;
  }
  else 
    snow_flux = -(energy->grnd_flux + energy->deltaH + energy->fusion);
  energy->refreeze_energy = 0; 
  coverage                = snow->coverage;
  snow_energy             = (*energy);
  soil_energy             = (*energy);
  snow_veg_var[WET]       = (*veg_var_wet);
  snow_veg_var[DRY]       = (*veg_var_dry);
  soil_veg_var[WET]       = (*veg_var_wet);
  soil_veg_var[DRY]       = (*veg_var_dry);
  step_snow               = (*snow);
  for ( lidx = 0; lidx < Nlayers; lidx++ ) {
    step_layer[WET][lidx] = layer_wet[lidx];
    step_layer[DRY][lidx] = layer_dry[lidx];
  }
  for ( lidx = 0; lidx < Nlayers; lidx++ ) {
    step_layer[WET][lidx].evap = 0;
    step_layer[DRY][lidx].evap = 0;
  }
  soil_veg_var[WET].canopyevap = 0;
  soil_veg_var[DRY].canopyevap = 0;
  snow_veg_var[WET].canopyevap = 0;
  snow_veg_var[DRY].canopyevap = 0;
  soil_veg_var[WET].throughfall = 0;
  soil_veg_var[DRY].throughfall = 0;
  snow_veg_var[WET].throughfall = 0;
  snow_veg_var[DRY].throughfall = 0;

  /********************************
    Set-up sub-time step controls
    (May eventually want to set this up so that it is also true 
    if frozen soils are present)
  ********************************/

  if(snow->swq > 0 || snow->snow_canopy > 0 || atmos->snowflag[NR]) {
    hidx      = 0;
    step_inc  = 1;
    endhidx   = hidx + NF;
    step_dt   = options.SNOW_STEP;
  }
  else {
    hidx      = NR;
    step_inc  = 1;
    endhidx   = hidx + step_inc;
    step_dt   = gp->dt;
  }

  /*******************************************
    Initialize sub-model time step variables
  *******************************************/

  // energy structure
  store_AlbedoOver        = 0;
  store_AlbedoUnder       = 0;
  store_AtmosLatent       = 0;
  store_AtmosLatentSub    = 0;
  store_AtmosSensible     = 0;
  store_LongOverIn        = 0;
  store_LongUnderIn       = 0;
  store_LongUnderOut      = 0;
  store_NetLongAtmos      = 0;
  store_NetLongOver       = 0;
  store_NetLongUnder      = 0;
  store_NetShortAtmos     = 0;
  store_NetShortGrnd      = 0;
  store_NetShortOver      = 0;
  store_NetShortUnder     = 0;
  store_ShortOverIn       = 0;
  store_ShortUnderIn      = 0;
  store_advected_sensible = 0;
  store_advection         = 0; 
  store_canopy_advection  = 0;
  store_canopy_latent     = 0;
  store_canopy_latent_sub = 0;
  store_canopy_sensible   = 0;
  store_canopy_refreeze   = 0;
  store_deltaCC           = 0; 
  store_deltaH            = 0;
  store_fusion            = 0;
  store_grnd_flux         = 0;
  store_latent            = 0;
  store_latent_sub        = 0;
  store_melt_energy       = 0;
  store_refreeze_energy   = 0; 
  store_sensible          = 0;
  store_snow_flux         = 0; 
  // snow structure
  last_snow_coverage      = snow->coverage;
  store_canopy_vapor_flux = 0;
  store_melt              = 0;
  store_vapor_flux        = 0;
  store_surface_flux      = 0;
  store_blowing_flux      = 0;
  // veg_var and cell structures
  for ( dist = 0; dist < Ndist; dist++ ) {
    store_throughfall[dist] = 0.;
    store_canopyevap[dist]  = 0.;
    for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
      store_layerevap[dist][lidx] = 0.;
    }
  }
  step_Wdew[WET]          = veg_var_wet->Wdew;
  step_Wdew[DRY]          = veg_var_wet->Wdew;
  // misc
  store_ppt[WET]          = 0;
  store_ppt[DRY]          = 0;
  step_prec[DRY]          = 0;
  store_aero_cond_used[0] = 0;
  store_aero_cond_used[1] = 0;
  (*snow_inflow)          = 0;
  for (p=0; p<N_PET_TYPES; p++)
    store_pot_evap[p] = 0;
  N_steps                 = 0;
      
  /*************************
    Compute surface fluxes 
  *************************/

  do {

    /** Solve energy balance for all sub-model time steps **/


    /* set air temperature and precipitation for this snow band */
    Tair = atmos->air_temp[hidx] + soil_con->Tfactor[band];
    step_prec[WET] = atmos->prec[hidx] / mu * soil_con->Pfactor[band];
    
    // initialize ground surface temperaure
    Tgrnd = energy->T[0];

    // initialize canopy terms
    Tcanopy = Tair;
    VPcanopy = atmos->vp[hidx];
    VPDcanopy = atmos->vpd[hidx];

    over_iter  = 0;
    tol_over   = 999;

    last_Tcanopy      = 999;
    last_snow_flux    = 999;

    // initialize bisection startup
    BISECT_OVER  = FALSE;
    A_tol_over   = 999;
    B_tol_over   = 999;

    // Compute mass flux of blowing snow
    if( !overstory && options.BLOWING && step_snow.swq > 0.) {
      Ls = (677. - 0.07 * step_snow.surf_temp) * JOULESPCAL * GRAMSPKG;
      step_snow.blowing_flux = CalcBlowingSnow((double) step_dt, Tair,
						step_snow.last_snow, step_snow.surf_water,
						wind[2], Ls, atmos->density[hidx],
						atmos->pressure[hidx],
						atmos->vp[hidx], roughness[2],
						ref_height[2], step_snow.depth,
						lag_one, sigma_slope,
						step_snow.surf_temp, iveg, Nveg, fetch,
						displacement[1], roughness[1],
						&step_snow.transport);
      if ( (int)step_snow.blowing_flux == ERROR ) {
        return ( ERROR );
      }
      step_snow.blowing_flux*=step_dt*SECPHOUR/RHO_W; /* m/time step */
    }
    else
      step_snow.blowing_flux = 0.0;

    do {

      /** Iterate for overstory solution **/

      over_iter++;
      last_tol_over  = tol_over;

      under_iter = 0;
      tol_under  = 999;
      UnderStory = 999;

      UNSTABLE_CNT = 0;
      
      // bisect understory
      BISECT_UNDER = FALSE;
      A_tol_under  = 999;
      B_tol_under  = 999;
      store_tol_under = 999;
      
      A_tol_over   = 999;
      B_tol_over   = 999;
      store_tol_over = 999;

      do {

	/** Iterate for understory solution - itererates to find snow flux **/

	under_iter++;
	last_tol_under = tol_under;

	if ( last_Tcanopy != 999 ) Tcanopy = (last_Tcanopy + Tcanopy) / 2.;
	last_Tcanopy       = Tcanopy;
	A_tol_over         = store_tol_over;
	A_Tcanopy          = Tcanopy;

	// update understory energy balance terms for iteration
	if ( last_snow_flux != 999 ) { 
	  if ( ( fabs(store_tol_under) > fabs(A_tol_under) 
		 && A_tol_under != 999 
		 && fabs(store_tol_under - A_tol_under) > 1. ) 
	       || tol_under < 0 ) { // stepped the correct way
	    UNSTABLE_CNT++;
	    if ( UNSTABLE_CNT > 3 || tol_under < 0 )
	      UNSTABLE_SNOW = TRUE;
	  }
	  else if ( !INCLUDE_SNOW ) { // stepped the wrong way
	    snow_flux = (last_snow_flux + iter_soil_energy.snow_flux) / 2.;
	  } 
	}
	last_snow_flux = snow_flux;
	A_tol_under    = store_tol_under;
	A_snow_flux    = snow_flux;

	snow_grnd_flux = -snow_flux;
	
	// Initialize structures for new iteration
	iter_snow_energy    = snow_energy;
	iter_soil_energy    = soil_energy;
	iter_snow_veg_var[WET] = snow_veg_var[WET];
	iter_snow_veg_var[DRY] = snow_veg_var[DRY];
	iter_soil_veg_var[WET] = soil_veg_var[WET];
	iter_soil_veg_var[DRY] = soil_veg_var[DRY];
	iter_snow           = step_snow;
	for ( lidx = 0; lidx < Nlayers; lidx++ ) {
	  iter_layer[WET][lidx] = step_layer[WET][lidx];
	  iter_layer[DRY][lidx] = step_layer[DRY][lidx];
	}
	iter_snow_veg_var[WET].Wdew = step_Wdew[WET];
	iter_snow_veg_var[DRY].Wdew = step_Wdew[DRY];
	iter_soil_veg_var[WET].Wdew = step_Wdew[WET];
	iter_soil_veg_var[DRY].Wdew = step_Wdew[DRY];
	for ( dist = 0; dist < Ndist; dist ++ ) {
	  iter_snow_veg_var[dist].canopyevap = 0;
	  iter_soil_veg_var[dist].canopyevap = 0;
	  for ( lidx = 0; lidx < Nlayers; lidx ++ ) 
	    iter_layer[dist][lidx].evap = 0;
        }
	for (q=0; q<3; q++) {
	  iter_aero_resist[q] = aero_resist[N_PET_TYPES][q];
	}
        iter_aero_resist_used[0] = aero_resist_used[0];
        iter_aero_resist_used[1] = aero_resist_used[1];
	iter_snow.canopy_vapor_flux = 0;
	iter_snow.vapor_flux = 0;
	iter_snow.surface_flux = 0;
        /* iter_snow.blowing_flux has already been reset to step_snow.blowing_flux */
	LongUnderOut       = iter_soil_energy.LongUnderOut;

	/** Solve snow accumulation, ablation and interception **/
	step_melt = solve_snow(overstory, BareAlbedo, LongUnderOut, 
			       gp->MIN_RAIN_TEMP, gp->MAX_SNOW_TEMP, 
			       Tcanopy, Tgrnd, Tair, dp, mu, 
			       step_prec[WET], snow_grnd_flux, gp->wind_h, 
			       &energy->AlbedoUnder, &step_Evap, Le, 
			       &LongUnderIn, &NetLongSnow, &NetShortGrnd, 
			       &NetShortSnow, &ShortUnderIn, &OldTSurf, 
			       iter_aero_resist, iter_aero_resist_used,
			       &coverage, &delta_coverage, 
			       &delta_snow_heat, displacement, 
			       gauge_correction, &step_melt_energy, 
			       &step_out_prec, &step_out_rain, &step_out_snow,
			       step_ppt, rainfall, ref_height, 
			       roughness, snow_inflow, snowfall, &surf_atten, 
			       wind, root, UNSTABLE_SNOW, options.Nnode, 
			       Nveg, iveg, band, step_dt, rec, hidx, veg_class,
			       &UnderStory, dmy, atmos, &(iter_snow_energy), 
			       iter_layer[DRY], iter_layer[WET], &(iter_snow), 
			       soil_con, &(iter_snow_veg_var[DRY]), 
			       &(iter_snow_veg_var[WET]));
      
// iter_snow_energy.sensible + iter_snow_energy.latent + iter_snow_energy.latent_sub + NetShortSnow + NetLongSnow + ( snow_grnd_flux + iter_snow_energy.advection - iter_snow_energy.deltaCC + iter_snow_energy.refreeze_energy + iter_snow_energy.advected_sensible ) * step_snow.coverage
        if ( step_melt == ERROR ) return (ERROR);

	/* Check that the snow surface temperature was estimated, if not
	   prepare to include thin snowpack in the estimation of the
	   snow-free surface energy balance */
	if ( ( iter_snow.surf_temp == 999 || UNSTABLE_SNOW ) 
	     && iter_snow.swq > 0 ) {
	  INCLUDE_SNOW = UnderStory + 1;
	  iter_soil_energy.advection = iter_snow_energy.advection;
	  iter_snow.surf_temp = step_snow.surf_temp;
	  step_melt_energy = 0;
	}
	else {
	  INCLUDE_SNOW = FALSE;
	}

	/**************************************************
          Solve Energy Balance Components at Soil Surface
        **************************************************/
	      
	Tsurf = calc_surf_energy_bal((*Le), LongUnderIn, NetLongSnow, 
				     NetShortGrnd, NetShortSnow, OldTSurf, 
				     ShortUnderIn, iter_snow.albedo, 
				     iter_snow_energy.latent, 
				     iter_snow_energy.latent_sub, 
				     iter_snow_energy.sensible, 
				     Tcanopy, VPDcanopy, 
				     VPcanopy, iter_snow_energy.advection, 
				     step_snow.coldcontent, delta_coverage, dp, 
				     ice0, step_melt_energy, moist0, mu, 
				     iter_snow.coverage, 
				     (step_snow.depth + iter_snow.depth) / 2., 
				     BareAlbedo, surf_atten, 
				     iter_snow.vapor_flux,
				     iter_aero_resist, iter_aero_resist_used,
				     displacement, &step_melt, step_ppt, 
				     rainfall, ref_height, roughness, 
				     snowfall, wind, root, INCLUDE_SNOW, 
				     UnderStory, options.Nnode, Nveg, band, 
				     step_dt, hidx, iveg, options.Nlayer, 
				     (int)overstory, rec, veg_class, atmos, 
				     &(dmy[rec]), &iter_soil_energy, 
				     iter_layer[DRY], iter_layer[WET], 
				     &(iter_snow), soil_con, 
				     &iter_soil_veg_var[DRY], &iter_soil_veg_var[WET], gp->nrecs); 

        if ( (int)Tsurf == ERROR ) {
          // Return error flag to skip rest of grid cell
          return ( ERROR );
        }

	if ( INCLUDE_SNOW ) {
	  /* store melt from thin snowpack */
	  step_ppt[WET] += step_melt;
	}
	
	/*****************************************
          Compute energy balance with atmosphere
        *****************************************/
	if ( iter_snow.snow && overstory && MAX_ITER > 0 ) {
	  // do this if overstory is active and energy balance is closed
	  Tcanopy = calc_atmos_energy_bal(iter_snow_energy.canopy_sensible,
					  iter_soil_energy.sensible, 
					  iter_snow_energy.canopy_latent, 
					  iter_soil_energy.latent, 
					  iter_snow_energy.canopy_latent_sub, 
					  iter_soil_energy.latent_sub, 
					  (*Le),
					  iter_snow_energy.NetLongOver, 
					  iter_soil_energy.NetLongUnder, 
					  iter_snow_energy.NetShortOver, 
					  iter_soil_energy.NetShortUnder, 
					  iter_aero_resist_used[1], Tair, 
					  atmos->density[hidx], 
					  atmos->vp[hidx], atmos->vpd[hidx], 
					  &iter_soil_energy.AtmosError, 
					  &iter_soil_energy.AtmosLatent,
					  &iter_soil_energy.AtmosLatentSub,
					  &iter_soil_energy.NetLongAtmos, 
					  &iter_soil_energy.NetShortAtmos, 
					  &iter_soil_energy.AtmosSensible, 
					  &VPcanopy, &VPDcanopy,
					  &iter_soil_energy.Tcanopy_fbflag,
					  &iter_soil_energy.Tcanopy_fbcount);
	  /* iterate to find Tcanopy which will solve the atmospheric energy
	     balance.  Since I do not know vp in the canopy, use the
	     sum of latent heats from the ground and foliage, and iterate
	     on the temperature used for the sensible heat flux from the
	     canopy air to the mixing level */
          if ( (int)Tcanopy == ERROR ) {
            // Return error flag to skip rest of grid cell
            return ( ERROR );
          }
	}
	else {
	  // else put surface fluxes into atmospheric flux storage so that 
	  // the model will continue to function
	  iter_soil_energy.AtmosLatent    = iter_soil_energy.latent;
	  iter_soil_energy.AtmosLatentSub = iter_soil_energy.latent_sub;
	  iter_soil_energy.AtmosSensible  = iter_soil_energy.sensible;
	  iter_soil_energy.NetLongAtmos   = iter_soil_energy.NetLongUnder;
	  iter_soil_energy.NetShortAtmos  = iter_soil_energy.NetShortUnder;
	}
	iter_soil_energy.Tcanopy = Tcanopy;
	iter_snow_energy.Tcanopy = Tcanopy;

	/*****************************************
          Compute iteration tolerance statistics 
        *****************************************/

	// compute understory tolerance
	if ( INCLUDE_SNOW || ( iter_snow.swq == 0 && delta_coverage == 0 ) ) {
	  store_tol_under = 0;
	  tol_under       = 0;
	}
	else {
	  store_tol_under = snow_flux - iter_soil_energy.snow_flux;
	  tol_under       = fabs(store_tol_under);
	}
	if ( fabs( tol_under - last_tol_under ) < GRND_TOL && tol_under > 1. )
	  tol_under = -999;

	// compute overstory tolerance
	if ( overstory && iter_snow.snow ) {
	  store_tol_over = Tcanopy - last_Tcanopy;
	  tol_over       = fabs( store_tol_over );
	}
	else {
	  store_tol_over = 0;
	  tol_over       = 0;
	}
		
      } while ( ( fabs( tol_under - last_tol_under ) > GRND_TOL )
		&& ( tol_under != 0 ) && (under_iter < MAX_ITER) );

    } while ( ( fabs( tol_over - last_tol_over ) > OVER_TOL 
		&& overstory ) && ( tol_over != 0 ) 
	      && (over_iter < MAX_ITER) );
 
    /**************************************
      Compute Potential Evap
    **************************************/
    // First, determine the stability correction used in the iteration
    if (iter_aero_resist_used[0] == HUGE_RESIST)
      stability_factor[0] = HUGE_RESIST;
    else
      stability_factor[0] = iter_aero_resist_used[0]/aero_resist[N_PET_TYPES][UnderStory];
    if (iter_aero_resist_used[1] == iter_aero_resist_used[0])
      stability_factor[1] = stability_factor[0];
    else {
      if (iter_aero_resist_used[1] == HUGE_RESIST)
        stability_factor[1] = HUGE_RESIST;
      else
        stability_factor[1] = iter_aero_resist_used[1]/aero_resist[N_PET_TYPES][1];
    }

    // Next, loop over pot_evap types and apply the correction to the relevant aerodynamic resistance
    for (p=0; p<N_PET_TYPES; p++) {
      if (stability_factor[0] == HUGE_RESIST)
        step_aero_resist[p][0] = HUGE_RESIST;
      else
        step_aero_resist[p][0] = aero_resist[p][UnderStory]*stability_factor[0];
      if (stability_factor[1] == HUGE_RESIST)
        step_aero_resist[p][1] = HUGE_RESIST;
      else
        step_aero_resist[p][1] = aero_resist[p][1]*stability_factor[1];
    }

    // Finally, compute pot_evap
    compute_pot_evap(veg_class, dmy, rec, gp->dt, atmos->shortwave[hidx], iter_soil_energy.NetLongAtmos, Tair, VPDcanopy, soil_con->elevation, step_aero_resist, iter_pot_evap);

    /**************************************
      Store sub-model time step variables 
    **************************************/

    snow_energy = iter_snow_energy;
    soil_energy = iter_soil_energy;
    snow_veg_var[WET] = iter_snow_veg_var[WET];
    snow_veg_var[DRY] = iter_snow_veg_var[DRY];
    soil_veg_var[WET] = iter_soil_veg_var[WET];
    soil_veg_var[DRY] = iter_soil_veg_var[DRY];
    step_snow = iter_snow;
    for(lidx = 0; lidx < options.Nlayer; lidx++) {
      step_layer[WET][lidx] = iter_layer[WET][lidx];
      step_layer[DRY][lidx] = iter_layer[DRY][lidx];
    }

    for(dist = 0; dist < Ndist; dist++) {

      if(iveg != Nveg) {
	if(step_snow.snow) {
	  store_throughfall[dist] += snow_veg_var[dist].throughfall;
	  store_canopyevap[dist]  += snow_veg_var[dist].canopyevap;
	  soil_veg_var[dist].Wdew  = snow_veg_var[dist].Wdew;
	}
	else {
	  store_throughfall[dist] += soil_veg_var[dist].throughfall;
	  store_canopyevap[dist]  += soil_veg_var[dist].canopyevap;
	  snow_veg_var[dist].Wdew  = soil_veg_var[dist].Wdew;
	}
        step_Wdew[dist] = soil_veg_var[dist].Wdew;
      }

      for(lidx = 0; lidx < options.Nlayer; lidx++)
	store_layerevap[dist][lidx] += step_layer[dist][lidx].evap;

      store_ppt[dist] += step_ppt[dist];
    }
    if (iter_aero_resist_used[0]>0)
      store_aero_cond_used[0] += 1/iter_aero_resist_used[0];
    else
      store_aero_cond_used[0] += HUGE_RESIST;
    if (iter_aero_resist_used[1]>0)
      store_aero_cond_used[1] += 1/iter_aero_resist_used[1];
    else
      store_aero_cond_used[1] += HUGE_RESIST;

    if(iveg != Nveg) 
      store_canopy_vapor_flux += step_snow.canopy_vapor_flux;
    store_melt         += step_melt;
    store_vapor_flux   += step_snow.vapor_flux;
    store_surface_flux += step_snow.surface_flux;
    store_blowing_flux += step_snow.blowing_flux;
      
    out_prec[0] += step_out_prec * mu;
    out_rain[0] += step_out_rain * mu;
    out_snow[0] += step_out_snow * mu;

    if ( INCLUDE_SNOW ) {
      /* copy needed flux terms to the snowpack */
      snow_energy.advected_sensible  = soil_energy.advected_sensible; 
      snow_energy.advection          = soil_energy.advection; 
      snow_energy.deltaCC            = soil_energy.deltaCC; 
      snow_energy.latent             = soil_energy.latent;
      snow_energy.latent_sub         = soil_energy.latent_sub;
      snow_energy.refreeze_energy    = soil_energy.refreeze_energy; 
      snow_energy.sensible           = soil_energy.sensible;
      snow_energy.snow_flux          = soil_energy.snow_flux; 
    }

    store_AlbedoOver        += snow_energy.AlbedoOver; 
    store_AlbedoUnder       += soil_energy.AlbedoUnder;
    store_AtmosLatent       += soil_energy.AtmosLatent;
    store_AtmosLatentSub    += soil_energy.AtmosLatentSub;
    store_AtmosSensible     += soil_energy.AtmosSensible;
    store_LongOverIn        += snow_energy.LongOverIn; 
    store_LongUnderIn       += LongUnderIn; 
    store_LongUnderOut      += soil_energy.LongUnderOut; 
    store_NetLongAtmos      += soil_energy.NetLongAtmos; 
    store_NetLongOver       += snow_energy.NetLongOver; 
    store_NetLongUnder      += soil_energy.NetLongUnder; 
    store_NetShortAtmos     += soil_energy.NetShortAtmos; 
    store_NetShortGrnd      += NetShortGrnd; 
    store_NetShortOver      += snow_energy.NetShortOver; 
    store_NetShortUnder     += soil_energy.NetShortUnder; 
    store_ShortOverIn       += snow_energy.ShortOverIn; 
    store_ShortUnderIn      += soil_energy.ShortUnderIn; 
    store_canopy_advection  += snow_energy.canopy_advection; 
    store_canopy_latent     += snow_energy.canopy_latent; 
    store_canopy_latent_sub += snow_energy.canopy_latent_sub; 
    store_canopy_sensible   += snow_energy.canopy_sensible; 
    store_canopy_refreeze   += snow_energy.canopy_refreeze; 
    store_deltaH            += soil_energy.deltaH; 
    store_fusion            += soil_energy.fusion; 
    store_grnd_flux         += soil_energy.grnd_flux; 
    store_latent            += soil_energy.latent; 
    store_latent_sub        += soil_energy.latent_sub; 
    store_melt_energy       += step_melt_energy;
    store_sensible          += soil_energy.sensible; 
    if ( step_snow.swq == 0 && INCLUDE_SNOW ) {
      if ( last_snow_coverage == 0 && step_prec > 0 ) last_snow_coverage = 1;
      store_advected_sensible += snow_energy.advected_sensible * last_snow_coverage; 
      store_advection         += snow_energy.advection * last_snow_coverage; 
      store_deltaCC           += snow_energy.deltaCC * last_snow_coverage; 
      store_snow_flux         += soil_energy.snow_flux * last_snow_coverage; 
      store_refreeze_energy   += snow_energy.refreeze_energy * last_snow_coverage; 
    }
    else if ( step_snow.snow || INCLUDE_SNOW ) {
      store_advected_sensible += snow_energy.advected_sensible * (step_snow.coverage + delta_coverage);
      store_advection         += snow_energy.advection * (step_snow.coverage + delta_coverage); 
      store_deltaCC           += snow_energy.deltaCC * (step_snow.coverage + delta_coverage); 
      store_snow_flux         += soil_energy.snow_flux * (step_snow.coverage + delta_coverage); 
      store_refreeze_energy   += snow_energy.refreeze_energy * (step_snow.coverage + delta_coverage); 
    }
    for (p=0; p<N_PET_TYPES; p++)
      store_pot_evap[p] += iter_pot_evap[p];

    /* increment time step */
    N_steps ++;
    hidx += step_inc;

  } while (hidx < endhidx);

  /************************************************
    Store snow variables for sub-model time steps 
  ************************************************/

  (*snow) = step_snow;
  snow->vapor_flux = store_vapor_flux;
  snow->blowing_flux = store_blowing_flux;
  snow->surface_flux = store_surface_flux;
  snow->canopy_vapor_flux = store_canopy_vapor_flux;
  (*Melt) = store_melt;
  snow->melt = store_melt;
  for(dist = 0; dist < 2; dist++) ppt[dist] = store_ppt[dist];

  /******************************************************
    Store energy flux averages for sub-model time steps 
  ******************************************************/

  (*energy) = soil_energy;
  energy->AlbedoOver        = store_AlbedoOver / (double)N_steps; 
  energy->AlbedoUnder       = store_AlbedoUnder / (double)N_steps;
  energy->AtmosLatent       = store_AtmosLatent / (double)N_steps; 
  energy->AtmosLatentSub    = store_AtmosLatentSub / (double)N_steps; 
  energy->AtmosSensible     = store_AtmosSensible / (double)N_steps; 
  energy->LongOverIn        = store_LongOverIn / (double)N_steps; 
  energy->LongUnderIn       = store_LongUnderIn / (double)N_steps; 
  energy->LongUnderOut      = store_LongUnderOut / (double)N_steps; 
  energy->NetLongAtmos      = store_NetLongAtmos / (double)N_steps; 
  energy->NetLongOver       = store_NetLongOver / (double)N_steps; 
  energy->NetLongUnder      = store_NetLongUnder / (double)N_steps; 
  energy->NetShortAtmos     = store_NetShortAtmos / (double)N_steps; 
  energy->NetShortGrnd      = store_NetShortGrnd / (double)N_steps; 
  energy->NetShortOver      = store_NetShortOver / (double)N_steps; 
  energy->NetShortUnder     = store_NetShortUnder / (double)N_steps; 
  energy->ShortOverIn       = store_ShortOverIn / (double)N_steps; 
  energy->ShortUnderIn      = store_ShortUnderIn / (double)N_steps; 
  energy->advected_sensible = store_advected_sensible / (double)N_steps; 
  energy->canopy_advection  = store_canopy_advection / (double)N_steps; 
  energy->canopy_latent     = store_canopy_latent / (double)N_steps; 
  energy->canopy_latent_sub = store_canopy_latent_sub / (double)N_steps; 
  energy->canopy_refreeze   = store_canopy_refreeze / (double)N_steps; 
  energy->canopy_sensible   = store_canopy_sensible / (double)N_steps; 
  energy->deltaH            = store_deltaH / (double)N_steps; 
  energy->fusion            = store_fusion / (double)N_steps; 
  energy->grnd_flux         = store_grnd_flux / (double)N_steps; 
  energy->latent            = store_latent / (double)N_steps; 
  energy->latent_sub        = store_latent_sub / (double)N_steps; 
  energy->melt_energy       = store_melt_energy / (double)N_steps;
  energy->sensible          = store_sensible / (double)N_steps; 
  if (snow->snow || INCLUDE_SNOW) {
    energy->advection       = store_advection / (double)N_steps; 
    energy->deltaCC         = store_deltaCC / (double)N_steps; 
    energy->refreeze_energy = store_refreeze_energy / (double)N_steps; 
    energy->snow_flux       = store_snow_flux / (double)N_steps; 
  }
  energy->Tfoliage          = snow_energy.Tfoliage;
  energy->Tfoliage_fbflag   = snow_energy.Tfoliage_fbflag;
  energy->Tfoliage_fbcount  = snow_energy.Tfoliage_fbcount;

// energy->AtmosSensible + energy->AtmosLatent + energy->AtmosLatentSub + energy->NetShortAtmos + energy->NetLongAtmos + energy->grnd_flux + energy->deltaH + energy->fusion + energy->advection - energy->deltaCC + energy->refreeze_energy + energy->advected_sensible

  /**********************************************************
    Store vegetation variable sums for sub-model time steps 
  **********************************************************/

  if(iveg != Nveg) {
    veg_var_wet->throughfall = store_throughfall[WET];
    veg_var_dry->throughfall = store_throughfall[DRY];
    veg_var_wet->canopyevap  = store_canopyevap[WET];
    veg_var_dry->canopyevap  = store_canopyevap[DRY];
    if(snow->snow) {
      veg_var_wet->Wdew        = snow_veg_var[WET].Wdew;
      veg_var_dry->Wdew        = snow_veg_var[DRY].Wdew;
    }
    else {
      veg_var_wet->Wdew        = soil_veg_var[WET].Wdew;
      veg_var_dry->Wdew        = soil_veg_var[DRY].Wdew;
    }
  }

  /**********************************************************
    Store soil layer variables for sub-model time steps 
  **********************************************************/

  for(lidx=0;lidx<Nlayers;lidx++) {
    layer_wet[lidx]      = step_layer[WET][lidx];
    layer_dry[lidx]      = step_layer[DRY][lidx];
    layer_wet[lidx].evap = store_layerevap[WET][lidx];
    layer_dry[lidx].evap = store_layerevap[DRY][lidx];
#if EXCESS_ICE
    evap_prior_wet[lidx] = store_layerevap[WET][lidx];
    evap_prior_dry[lidx] = store_layerevap[DRY][lidx];
#endif
  }
  if (store_aero_cond_used[0]>0 && store_aero_cond_used[0]<HUGE_RESIST)
    aero_resist_used[0] = 1/(store_aero_cond_used[0]/(double)N_steps);
  else if (store_aero_cond_used[0]>=HUGE_RESIST)
    aero_resist_used[0] = 0;
  else
    aero_resist_used[0] = HUGE_RESIST;
  if (store_aero_cond_used[1]>0 && store_aero_cond_used[1]<HUGE_RESIST)
    aero_resist_used[1] = 1/(store_aero_cond_used[1]/(double)N_steps);
  else if (store_aero_cond_used[1]>=HUGE_RESIST)
    aero_resist_used[1] = 0;
  else
    aero_resist_used[1] = HUGE_RESIST;
  for (p=0; p<N_PET_TYPES; p++)
    pot_evap[p] = store_pot_evap[p]/(double)N_steps;

  for (p=0; p<N_PET_TYPES; p++) {
    free((char *)step_aero_resist[p]);
  }
  free((char *)step_aero_resist);

  /********************************************************
    Compute Runoff, Baseflow, and Soil Moisture Transport
  ********************************************************/

#if EXCESS_ICE
  if(SubsidenceUpdate != 2){
#endif
    (*inflow_wet) = ppt[WET];
    (*inflow_dry) = ppt[DRY];

    ErrorFlag = runoff(cell_wet, cell_dry, energy, soil_con, ppt, 
#if EXCESS_ICE
		       SubsidenceUpdate,
#endif
#if SPATIAL_FROST
		       soil_con->frost_fract,
#endif // SPATIAL_FROST
		       mu, gp->dt, options.Nnode, band, rec, iveg);
    
    return( ErrorFlag );
#if EXCESS_ICE
  }
#endif

  return(0);
}
예제 #2
0
/******************************************************************************
* @brief        This routine computes all surface fluxes
******************************************************************************/
int
surface_fluxes(bool                 overstory,
               double               BareAlbedo,
               double               ice0,
               double               moist0,
               double               surf_atten,
               double              *Melt,
               double              *Le,
               double              *aero_resist,
               double              *displacement,
               double              *gauge_correction,
               double              *out_prec,
               double              *out_rain,
               double              *out_snow,
               double              *ref_height,
               double              *roughness,
               double              *snow_inflow,
               double              *wind,
               double              *root,
               size_t               Nlayers,
               size_t               Nveg,
               unsigned short       band,
               double               dp,
               unsigned short       iveg,
               unsigned short       veg_class,
               force_data_struct   *force,
               dmy_struct          *dmy,
               energy_bal_struct   *energy,
               global_param_struct *gp,
               cell_data_struct    *cell,
               snow_data_struct    *snow,
               soil_con_struct     *soil_con,
               veg_var_struct      *veg_var,
               double               lag_one,
               double               sigma_slope,
               double               fetch,
               double              *CanopLayerBnd)
{
    extern veg_lib_struct   *vic_run_veg_lib;
    extern option_struct     options;
    extern parameters_struct param;

    int                      MAX_ITER_GRND_CANOPY;
    int                      ErrorFlag;
    int                      INCLUDE_SNOW = false;
    int                      UNSTABLE_CNT;
    int                      UNSTABLE_SNOW = false;
    int                      N_steps;
    int                      UnderStory;
    size_t                   hidx; // index of initial element of atmos array
    size_t                   step_inc; // number of atmos array elements to skip per surface fluxes step
    size_t                   endhidx; // index of final element of atmos array
    double                   step_dt; // time length of surface fluxes step (in seconds)
    size_t                   lidx;
    int                      over_iter;
    int                      under_iter;
    int                      q;
    double                   Ls;
    double                   LongUnderIn; // inmoing LW to ground surface
    double                   LongUnderOut; // outgoing LW from ground surface
    double                   NetLongSnow; // net LW over snowpack
    double                   NetShortSnow; // net SW over understory
    double                   NetShortGrnd; // net SW over snow-free surface
    double                   OldTSurf; // previous snow surface temperature
    double                   ShortUnderIn; // incoming SW to understory
    double                   Tair; // air temperature
    double                   Tcanopy; // canopy air temperature
    double                   Tgrnd; // soil surface temperature
    double                   Tsurf; // ground surface temperature
    double                   VPDcanopy; // vapor pressure deficit in canopy/atmos
    double                   VPcanopy; // vapor pressure in canopy/atmos
    double                   coverage; // mid-step snow cover fraction
    double                   delta_coverage; // change in snow cover fraction
    double                   delta_snow_heat; // change in snowpack heat storage
    double                   last_Tcanopy;
    double                   last_snow_coverage; // previous snow covered area
    double                   last_snow_flux;
    double                   last_tol_under; // previous surface iteration tol
    double                   last_tol_over; // previous overstory iteration tol
    double                   ppt; // precipitation/melt reaching soil surface
    double                   rainfall; // rainfall
    double                   snowfall; // snowfall
    double                   snow_flux; // heat flux through snowpack
    double                   snow_grnd_flux; // ground heat flux into snowpack
    double                   tol_under;
    double                   tol_over;
    double                  *aero_resist_used;
    double                  *inflow;
    layer_data_struct       *layer;

    // Step-specific quantities
    double                   step_Wdew;
    double                   step_melt;
    double                   step_melt_energy; /* energy used to reduce snow coverage */
    double                   step_out_prec;
    double                   step_out_rain;
    double                   step_out_snow;
    double                   step_ppt;
    double                   step_prec;

    // Quantities that need to be summed or averaged over multiple snow steps
    // energy structure
    double            store_AlbedoOver;
    double            store_AlbedoUnder;
    double            store_AtmosLatent;
    double            store_AtmosLatentSub;
    double            store_AtmosSensible;
    double            store_LongOverIn;
    double            store_LongUnderIn;
    double            store_LongUnderOut;
    double            store_NetLongAtmos;
    double            store_NetLongOver;
    double            store_NetLongUnder;
    double            store_NetShortAtmos;
    double            store_NetShortGrnd;
    double            store_NetShortOver;
    double            store_NetShortUnder;
    double            store_ShortOverIn;
    double            store_ShortUnderIn;
    double            store_advected_sensible;
    double            store_advection;
    double            store_canopy_advection;
    double            store_canopy_latent;
    double            store_canopy_latent_sub;
    double            store_canopy_sensible;
    double            store_canopy_refreeze;
    double            store_deltaCC;
    double            store_deltaH;
    double            store_fusion;
    double            store_grnd_flux;
    double            store_latent;
    double            store_latent_sub;
    double            store_melt_energy;
    double            store_refreeze_energy;
    double            store_sensible;
    double            store_snow_flux;
    // snow structure
    double            store_canopy_vapor_flux;
    double            store_melt;
    double            store_vapor_flux;
    double            store_blowing_flux;
    double            store_surface_flux;
    // veg_var structure
    double            store_canopyevap;
    double            store_throughfall;
    // cell structure
    double            store_layerevap[MAX_LAYERS];
    double            store_ppt;
    double            store_aero_cond_used[2];
    double            store_pot_evap;

    // Structures holding values for current snow step
    energy_bal_struct snow_energy;    // energy fluxes at snowpack surface
    energy_bal_struct soil_energy;    // energy fluxes at soil surface
    veg_var_struct    snow_veg_var;    // veg fluxes/storages in presence of snow
    veg_var_struct    soil_veg_var;    // veg fluxes/storages in soil energy balance
    snow_data_struct  step_snow;
    layer_data_struct step_layer[MAX_LAYERS];

    // Structures holding values for current iteration
    energy_bal_struct iter_snow_energy;    // energy fluxes at snowpack surface
    energy_bal_struct iter_soil_energy;    // energy fluxes at soil surface
    veg_var_struct    iter_snow_veg_var;    // veg fluxes/storages in presence of snow
    veg_var_struct    iter_soil_veg_var;    // veg fluxes/storages in soil energy balance
    snow_data_struct  iter_snow;
    layer_data_struct iter_layer[MAX_LAYERS];
    double            iter_aero_resist[3];
    double            iter_aero_resist_veg[3];
    double            iter_aero_resist_used[2];
    double            iter_pot_evap;
#ifdef VCS_V5
    double            iter_pot_evap_veg;
    double            iter_pot_evap_soil;
#endif

    // handle bisection of understory solution
    double            store_tol_under;
    double            A_tol_under;

    // handle bisection of overstory solution
    double            store_tol_over;

    // Carbon cycling
    double            dryFrac;
    double           *LAIlayer = NULL;
    double           *faPAR = NULL;
    size_t            cidx;
    double            store_gc;
    double           *store_gsLayer = NULL;
    double            store_Ci;
    double            store_GPP;
    double            store_Rdark;
    double            store_Rphoto;
    double            store_Rmaint;
    double            store_Rgrowth;
    double            store_Raut;
    double            store_NPP;

    if (options.CLOSE_ENERGY) {
        MAX_ITER_GRND_CANOPY = 10;
    }
    else {
        MAX_ITER_GRND_CANOPY = 0;
    }

    if (options.CARBON) {
        store_gsLayer = calloc(options.Ncanopy, sizeof(*store_gsLayer));
        check_alloc_status(store_gsLayer, "Memory allocation error.");
    }

    /***********************************************************************
       Set temporary variables for convenience
    ***********************************************************************/
    aero_resist_used = cell->aero_resist;
    inflow = &(cell->inflow);
    layer = cell->layer;

    /***********************************************************************
       Set temporary variables - preserves original values until iterations
       are completed
    ***********************************************************************/

    energy->advection = 0;
    energy->deltaCC = 0;
    if (snow->swq > 0) {
        snow_flux = energy->snow_flux;
    }
    else {
        snow_flux = -(energy->grnd_flux + energy->deltaH + energy->fusion);
    }
    energy->refreeze_energy = 0;
    coverage = snow->coverage;
    snow_energy = (*energy);
    soil_energy = (*energy);
    iter_soil_energy = (*energy);
    snow_veg_var = (*veg_var);
    soil_veg_var = (*veg_var);
    step_snow = (*snow);
    for (lidx = 0; lidx < Nlayers; lidx++) {
        step_layer[lidx] = layer[lidx];
    }
    for (lidx = 0; lidx < Nlayers; lidx++) {
        step_layer[lidx].evap = 0;
    }
    soil_veg_var.canopyevap = 0;
    snow_veg_var.canopyevap = 0;
    soil_veg_var.throughfall = 0;
    snow_veg_var.throughfall = 0;

    /********************************
       Set-up sub-time step controls
       (May eventually want to set this up so that it is also true
       if frozen soils are present)
    ********************************/

    if (snow->swq > 0 || snow->snow_canopy > 0 || force->snowflag[NR]) {
        hidx = 0;
        step_inc = 1;
        endhidx = hidx + NF;
        step_dt = gp->snow_dt;
    }
    else {
        hidx = NR;
        step_inc = 1;
        endhidx = hidx + step_inc;
        step_dt = gp->dt;
    }

    /*******************************************
       Initialize sub-model time step variables
    *******************************************/

    // energy structure
    store_AlbedoOver = 0;
    store_AlbedoUnder = 0;
    store_AtmosLatent = 0;
    store_AtmosLatentSub = 0;
    store_AtmosSensible = 0;
    store_LongOverIn = 0;
    store_LongUnderIn = 0;
    store_LongUnderOut = 0;
    store_NetLongAtmos = 0;
    store_NetLongOver = 0;
    store_NetLongUnder = 0;
    store_NetShortAtmos = 0;
    store_NetShortGrnd = 0;
    store_NetShortOver = 0;
    store_NetShortUnder = 0;
    store_ShortOverIn = 0;
    store_ShortUnderIn = 0;
    store_advected_sensible = 0;
    store_advection = 0;
    store_canopy_advection = 0;
    store_canopy_latent = 0;
    store_canopy_latent_sub = 0;
    store_canopy_sensible = 0;
    store_canopy_refreeze = 0;
    store_deltaCC = 0;
    store_deltaH = 0;
    store_fusion = 0;
    store_grnd_flux = 0;
    store_latent = 0;
    store_latent_sub = 0;
    store_melt_energy = 0;
    store_refreeze_energy = 0;
    store_sensible = 0;
    store_snow_flux = 0;
    // snow structure
    last_snow_coverage = snow->coverage;
    store_canopy_vapor_flux = 0;
    store_melt = 0;
    store_vapor_flux = 0;
    store_surface_flux = 0;
    store_blowing_flux = 0;
    // veg_var and cell structures
    store_throughfall = 0.;
    store_canopyevap = 0.;
    for (lidx = 0; lidx < options.Nlayer; lidx++) {
        store_layerevap[lidx] = 0.;
    }
    step_Wdew = veg_var->Wdew;
    // misc
    store_ppt = 0;
    store_aero_cond_used[0] = 0;
    store_aero_cond_used[1] = 0;
    (*snow_inflow) = 0;
    store_pot_evap = 0;
    N_steps = 0;

    // Carbon cycling
    if (options.CARBON) {
        store_gc = 0;
        for (cidx = 0; cidx < options.Ncanopy; cidx++) {
            store_gsLayer[cidx] = 0;
        }
        store_Ci = 0;
        store_GPP = 0;
        store_Rdark = 0;
        store_Rphoto = 0;
        store_Rmaint = 0;
        store_Rgrowth = 0;
        store_Raut = 0;
        store_NPP = 0;
    }

    /*************************
       Compute surface fluxes
    *************************/

    do
    {
        /** Solve energy balance for all sub-model time steps **/


        /* set air temperature and precipitation for this snow band */
        Tair = force->air_temp[hidx] + soil_con->Tfactor[band];
        step_prec = force->prec[hidx] * soil_con->Pfactor[band];

        // initialize ground surface temperaure
        Tgrnd = energy->T[0];

        // initialize canopy terms
        Tcanopy = Tair;
        VPcanopy = force->vp[hidx];
        VPDcanopy = force->vpd[hidx];

        over_iter = 0;
        tol_over = 999;

        last_Tcanopy = 999;
        last_snow_flux = 999;

        // compute LAI and absorbed PAR per canopy layer
        if (options.CARBON && iveg < Nveg) {
            LAIlayer = calloc(options.Ncanopy, sizeof(*LAIlayer));
            check_alloc_status(LAIlayer, "Memory allocation error.");
            faPAR = calloc(options.Ncanopy, sizeof(*faPAR));
            check_alloc_status(faPAR, "Memory allocation error.");

            /* Compute absorbed PAR per ground area per canopy layer (W/m2)
               normalized to PAR = 1 W, i.e. the canopy albedo in the PAR
               range (alb_total ~ 0.45*alb_par + 0.55*alb_other) */
            faparl(CanopLayerBnd,
                   veg_var->LAI,
                   soil_con->AlbedoPar,
                   force->coszen[hidx],
                   force->fdir[hidx],
                   LAIlayer,
                   faPAR);

            /* Convert to absolute (unnormalized) absorbed PAR per leaf area per canopy layer
               (umol(photons)/m2 leaf area / s); dividing by Epar converts PAR from W to umol(photons)/s */
            veg_var->aPAR = 0;
            for (cidx = 0; cidx < options.Ncanopy; cidx++) {
                if (LAIlayer[cidx] > 1e-10) {
                    veg_var->aPARLayer[cidx] =
                        (force->par[hidx] /
                         param.PHOTO_EPAR) * faPAR[cidx] / LAIlayer[cidx];
                    veg_var->aPAR += force->par[hidx] * faPAR[cidx] /
                                     LAIlayer[cidx];
                }
                else {
                    veg_var->aPARLayer[cidx] = force->par[hidx] /
                                               param.PHOTO_EPAR *
                                               faPAR[cidx] / 1e-10;
                    veg_var->aPAR += force->par[hidx] * faPAR[cidx] / 1e-10;
                }
            }
            free((char*) LAIlayer);
            free((char*) faPAR);
        }

        // Compute mass flux of blowing snow
        if (!overstory && options.BLOWING && step_snow.swq > 0.) {
            Ls = calc_latent_heat_of_sublimation(step_snow.surf_temp);
            step_snow.blowing_flux = CalcBlowingSnow(step_dt, Tair,
                                                     step_snow.last_snow,
                                                     step_snow.surf_water,
                                                     wind[2], Ls,
                                                     force->density[hidx],
                                                     force->vp[hidx],
                                                     roughness[2],
                                                     ref_height[2],
                                                     step_snow.depth,
                                                     lag_one, sigma_slope,
                                                     step_snow.surf_temp, iveg,
                                                     Nveg, fetch,
                                                     displacement[1],
                                                     roughness[1],
                                                     &step_snow.transport);
            if ((int) step_snow.blowing_flux == ERROR) {
                return (ERROR);
            }
            step_snow.blowing_flux *= step_dt / CONST_RHOFW; /* m/time step */
        }
        else {
            step_snow.blowing_flux = 0.0;
        }

        do
        {
            /** Iterate for overstory solution **/

            over_iter++;
            last_tol_over = tol_over;

            under_iter = 0;
            tol_under = 999;
            UnderStory = 999;

            UNSTABLE_CNT = 0;

            // bisect understory
            A_tol_under = 999;
            store_tol_under = 999;

            store_tol_over = 999;

            do
            {
                /** Iterate for understory solution - itererates to find snow flux **/

                under_iter++;
                last_tol_under = tol_under;

                if (last_Tcanopy != 999) {
                    Tcanopy = (last_Tcanopy + Tcanopy) / 2.;
                }
                last_Tcanopy = Tcanopy;

                // update understory energy balance terms for iteration
                if (last_snow_flux != 999) {
                    if ((fabs(store_tol_under) > fabs(A_tol_under) &&
                         A_tol_under != 999 &&
                         fabs(store_tol_under - A_tol_under) > 1.) ||
                        tol_under < 0) { // stepped the correct way
                        UNSTABLE_CNT++;
                        if (UNSTABLE_CNT > 3 || tol_under < 0) {
                            UNSTABLE_SNOW = true;
                        }
                    }
                    else if (!INCLUDE_SNOW) { // stepped the wrong way
                        snow_flux =
                            (last_snow_flux + iter_soil_energy.snow_flux) / 2.;
                    }
                }
                last_snow_flux = snow_flux;
                A_tol_under = store_tol_under;

                snow_grnd_flux = -snow_flux;

                // Initialize structures for new iteration
                iter_snow_energy = snow_energy;
                iter_soil_energy = soil_energy;
                iter_snow_veg_var = snow_veg_var;
                iter_soil_veg_var = soil_veg_var;
                iter_snow = step_snow;
                for (lidx = 0; lidx < Nlayers; lidx++) {
                    iter_layer[lidx] = step_layer[lidx];
                }
                iter_snow_veg_var.Wdew = step_Wdew;
                iter_soil_veg_var.Wdew = step_Wdew;
                iter_snow_veg_var.canopyevap = 0;
                iter_soil_veg_var.canopyevap = 0;
                for (lidx = 0; lidx < Nlayers; lidx++) {
                    iter_layer[lidx].evap = 0;
                }
                for (q = 0; q < 3; q++) {
                    iter_aero_resist[q] = aero_resist[q];
                    iter_aero_resist_veg[q] = aero_resist[q];
                }
                iter_aero_resist_used[0] = aero_resist_used[0];
                iter_aero_resist_used[1] = aero_resist_used[1];
                iter_snow.canopy_vapor_flux = 0;
                iter_snow.vapor_flux = 0;
                iter_snow.surface_flux = 0;
                /* iter_snow.blowing_flux has already been reset to step_snow.blowing_flux */
                LongUnderOut = iter_soil_energy.LongUnderOut;
                dryFrac = -1;

                /** Solve snow accumulation, ablation and interception **/
                step_melt = solve_snow(overstory, BareAlbedo, LongUnderOut,
                                       param.SNOW_MIN_RAIN_TEMP,
                                       param.SNOW_MAX_SNOW_TEMP,
                                       Tcanopy, Tgrnd, Tair,
                                       step_prec, snow_grnd_flux,
                                       &energy->AlbedoUnder, Le,
                                       &LongUnderIn, &NetLongSnow,
                                       &NetShortGrnd,
                                       &NetShortSnow, &ShortUnderIn, &OldTSurf,
                                       iter_aero_resist, iter_aero_resist_used,
                                       &coverage, &delta_coverage,
                                       &delta_snow_heat, displacement,
                                       gauge_correction, &step_melt_energy,
                                       &step_out_prec, &step_out_rain,
                                       &step_out_snow,
                                       &step_ppt, &rainfall, ref_height,
                                       roughness, snow_inflow, &snowfall,
                                       &surf_atten,
                                       wind, root, UNSTABLE_SNOW,
                                       Nveg, iveg, band, step_dt, hidx,
                                       veg_class,
                                       &UnderStory, CanopLayerBnd, &dryFrac,
                                       dmy, force, &(iter_snow_energy),
                                       iter_layer, &(iter_snow),
                                       soil_con,
                                       &(iter_snow_veg_var));

                if (step_melt == ERROR) {
                    return (ERROR);
                }

                /* Check that the snow surface temperature was estimated, if not
                   prepare to include thin snowpack in the estimation of the
                   snow-free surface energy balance */
                if ((iter_snow.surf_temp == 999 || UNSTABLE_SNOW) &&
                    iter_snow.swq > 0) {
                    INCLUDE_SNOW = UnderStory + 1;
                    iter_soil_energy.advection = iter_snow_energy.advection;
                    iter_snow.surf_temp = step_snow.surf_temp;
                    step_melt_energy = 0;
                }
                else {
                    INCLUDE_SNOW = false;
                }

                if (iter_snow.snow) {
                    iter_aero_resist_veg[0] = iter_aero_resist_used[0];
                    iter_aero_resist_veg[1] = iter_aero_resist_used[1];
                }

                /**************************************************
                   Solve Energy Balance Components at Soil Surface
                **************************************************/

                Tsurf = calc_surf_energy_bal((*Le), LongUnderIn, NetLongSnow,
                                             NetShortGrnd, NetShortSnow,
                                             OldTSurf,
                                             ShortUnderIn, iter_snow.albedo,
                                             iter_snow_energy.latent,
                                             iter_snow_energy.latent_sub,
                                             iter_snow_energy.sensible,
                                             Tcanopy, VPDcanopy,
                                             VPcanopy,
                                             delta_coverage, dp,
                                             ice0, step_melt_energy, moist0,
                                             iter_snow.coverage,
                                             (step_snow.depth + iter_snow.depth) / 2.,
                                             BareAlbedo, surf_atten,
                                             iter_aero_resist, iter_aero_resist_veg, iter_aero_resist_used,
                                             displacement, &step_melt, &step_ppt,
                                             rainfall, ref_height, roughness,
                                             snowfall, wind, root, INCLUDE_SNOW,
                                             UnderStory, options.Nnode, Nveg,
                                             step_dt, hidx, iveg,
                                             (int) overstory, veg_class,
                                             CanopLayerBnd, &dryFrac, force,
                                             dmy, &iter_soil_energy,
                                             iter_layer,
                                             &(iter_snow), soil_con,
                                             &iter_soil_veg_var);

                if ((int) Tsurf == ERROR) {
                    // Return error flag to skip rest of grid cell
                    return (ERROR);
                }

                if (INCLUDE_SNOW) {
                    /* store melt from thin snowpack */
                    step_ppt += step_melt;
                }

                /*****************************************
                   Compute energy balance with atmosphere
                *****************************************/
                if (iter_snow.snow && overstory) {
                    // do this if overstory is active and energy balance is closed
                    Tcanopy = calc_atmos_energy_bal(
                        iter_snow_energy.canopy_sensible,
                        iter_soil_energy.sensible,
                        iter_snow_energy.canopy_latent,
                        iter_soil_energy.latent,
                        iter_snow_energy.canopy_latent_sub,
                        iter_soil_energy.latent_sub,
                        iter_snow_energy.NetLongOver,
                        iter_soil_energy.NetLongUnder,
                        iter_snow_energy.NetShortOver,
                        iter_soil_energy.NetShortUnder,
                        iter_aero_resist_veg[1], Tair,
                        force->density[hidx],
                        &iter_soil_energy.AtmosError,
                        &iter_soil_energy.AtmosLatent,
                        &iter_soil_energy.AtmosLatentSub,
                        &iter_soil_energy.NetLongAtmos,
                        &iter_soil_energy.NetShortAtmos,
                        &iter_soil_energy.AtmosSensible,
                        &iter_soil_energy.Tcanopy_fbflag,
                        &iter_soil_energy.Tcanopy_fbcount);

                    /* iterate to find Tcanopy which will solve the atmospheric energy
                       balance.  Since I do not know vp in the canopy, use the
                       sum of latent heats from the ground and foliage, and iterate
                       on the temperature used for the sensible heat flux from the
                       canopy air to the mixing level */
                    if ((int) Tcanopy == ERROR) {
                        // Return error flag to skip rest of grid cell
                        return (ERROR);
                    }
                }
                else {
                    // else put surface fluxes into atmospheric flux storage so that
                    // the model will continue to function
                    iter_soil_energy.AtmosLatent = iter_soil_energy.latent;
                    iter_soil_energy.AtmosLatentSub =
                        iter_soil_energy.latent_sub;
                    iter_soil_energy.AtmosSensible = iter_soil_energy.sensible;
                    iter_soil_energy.NetLongAtmos =
                        iter_soil_energy.NetLongUnder;
                    iter_soil_energy.NetShortAtmos =
                        iter_soil_energy.NetShortUnder;
                }
                iter_soil_energy.Tcanopy = Tcanopy;
                iter_snow_energy.Tcanopy = Tcanopy;

                /*****************************************
                   Compute iteration tolerance statistics
                *****************************************/

                // compute understory tolerance
                if (INCLUDE_SNOW ||
                    (iter_snow.swq == 0 && delta_coverage == 0)) {
                    store_tol_under = 0;
                    tol_under = 0;
                }
                else {
                    store_tol_under = snow_flux - iter_soil_energy.snow_flux;
                    tol_under = fabs(store_tol_under);
                }
                if (fabs(tol_under - last_tol_under) < param.TOL_GRND &&
                    tol_under >
                    1.) {
                    tol_under = -999;
                }

                // compute overstory tolerance
                if (overstory && iter_snow.snow) {
                    store_tol_over = Tcanopy - last_Tcanopy;
                    tol_over = fabs(store_tol_over);
                }
                else {
                    store_tol_over = 0;
                    tol_over = 0;
                }
            }
            while ((fabs(tol_under - last_tol_under) > param.TOL_GRND) &&
                   (tol_under != 0) && (under_iter < MAX_ITER_GRND_CANOPY));
        }
        while ((fabs(tol_over - last_tol_over) > param.TOL_OVER &&
                overstory) && (tol_over != 0) &&
               (over_iter < MAX_ITER_GRND_CANOPY));

        /**************************************
           Compute GPP, Raut, and NPP
        **************************************/
        if (options.CARBON) {
            if (iveg < Nveg && !step_snow.snow && dryFrac > 0) {
                canopy_assimilation(vic_run_veg_lib[veg_class].Ctype,
                                    vic_run_veg_lib[veg_class].MaxCarboxRate,
                                    vic_run_veg_lib[veg_class].MaxETransport,
                                    vic_run_veg_lib[veg_class].CO2Specificity,
                                    iter_soil_veg_var.NscaleFactor,
                                    Tair,
                                    force->shortwave[hidx],
                                    iter_soil_veg_var.aPARLayer,
                                    soil_con->elevation,
                                    force->Catm[hidx],
                                    CanopLayerBnd,
                                    veg_var->LAI,
                                    "rs",
                                    iter_soil_veg_var.rsLayer,
                                    &(iter_soil_veg_var.rc),
                                    &(iter_soil_veg_var.Ci),
                                    &(iter_soil_veg_var.GPP),
                                    &(iter_soil_veg_var.Rdark),
                                    &(iter_soil_veg_var.Rphoto),
                                    &(iter_soil_veg_var.Rmaint),
                                    &(iter_soil_veg_var.Rgrowth),
                                    &(iter_soil_veg_var.Raut),
                                    &(iter_soil_veg_var.NPP));
                /* Adjust by fraction of canopy that was dry and account for any other inhibition`*/
                dryFrac *= iter_soil_veg_var.NPPfactor;
                iter_soil_veg_var.GPP *= dryFrac;
                iter_soil_veg_var.Rdark *= dryFrac;
                iter_soil_veg_var.Rphoto *= dryFrac;
                iter_soil_veg_var.Rmaint *= dryFrac;
                iter_soil_veg_var.Rgrowth *= dryFrac;
                iter_soil_veg_var.Raut *= dryFrac;
                iter_soil_veg_var.NPP *= dryFrac;
                /* Adjust by veg cover fraction */
                iter_soil_veg_var.GPP *= iter_soil_veg_var.fcanopy;
                iter_soil_veg_var.Rdark *= iter_soil_veg_var.fcanopy;
                iter_soil_veg_var.Rphoto *= iter_soil_veg_var.fcanopy;
                iter_soil_veg_var.Rmaint *= iter_soil_veg_var.fcanopy;
                iter_soil_veg_var.Rgrowth *= iter_soil_veg_var.fcanopy;
                iter_soil_veg_var.Raut *= iter_soil_veg_var.fcanopy;
                iter_soil_veg_var.NPP *= iter_soil_veg_var.fcanopy;
            }
            else {
                iter_soil_veg_var.rc = param.HUGE_RESIST;
                for (cidx = 0; cidx < options.Ncanopy; cidx++) {
                    iter_soil_veg_var.rsLayer[cidx] = param.HUGE_RESIST;
                }
                iter_soil_veg_var.Ci = 0;
                iter_soil_veg_var.GPP = 0;
                iter_soil_veg_var.Rdark = 0;
                iter_soil_veg_var.Rphoto = 0;
                iter_soil_veg_var.Rmaint = 0;
                iter_soil_veg_var.Rgrowth = 0;
                iter_soil_veg_var.Raut = 0;
                iter_soil_veg_var.NPP = 0;
            }
        }

        /**************************************
           Compute Potential Evap
        **************************************/

        compute_pot_evap(gp->model_steps_per_day,
                         vic_run_veg_lib[veg_class].rmin,
                         iter_soil_veg_var.albedo, force->shortwave[hidx],
                         iter_soil_energy.NetLongAtmos,
                         vic_run_veg_lib[veg_class].RGL, Tair, VPDcanopy,
                         iter_soil_veg_var.LAI, soil_con->elevation,
                         iter_aero_resist_veg,
                         vic_run_veg_lib[veg_class].overstory,
                         vic_run_veg_lib[veg_class].rarc,
                         iter_soil_veg_var.fcanopy, iter_aero_resist_used[0],
                         &iter_pot_evap
#ifdef VCS_V5
                         ,
                         &iter_pot_evap_veg,
                         &iter_pot_evap_soil
#endif
                         );
#ifdef VCS_V5
        cell->VCS.pot_evap_veg_daily    += iter_pot_evap_veg;
        cell->VCS.pot_evap_soil_daily   += iter_pot_evap_soil;
        cell->VCS.pot_evap_total_daily  += iter_pot_evap;
#endif
        /**************************************
           Store sub-model time step variables
        **************************************/

        snow_energy = iter_snow_energy;
        soil_energy = iter_soil_energy;
        snow_veg_var = iter_snow_veg_var;
        soil_veg_var = iter_soil_veg_var;
        step_snow = iter_snow;
        for (lidx = 0; lidx < options.Nlayer; lidx++) {
            step_layer[lidx] = iter_layer[lidx];
        }

        if (iveg != Nveg) {
            if (step_snow.snow) {
                store_throughfall += snow_veg_var.throughfall;
                store_canopyevap += snow_veg_var.canopyevap;
                soil_veg_var.Wdew = snow_veg_var.Wdew;
            }
            else {
                store_throughfall += soil_veg_var.throughfall;
                store_canopyevap += soil_veg_var.canopyevap;
                snow_veg_var.Wdew = soil_veg_var.Wdew;
            }
            step_Wdew = soil_veg_var.Wdew;
            if (options.CARBON) {
                store_gc += 1 / soil_veg_var.rc;
                for (cidx = 0; cidx < options.Ncanopy; cidx++) {
                    store_gsLayer[cidx] += 1 / soil_veg_var.rsLayer[cidx];
                }
                store_Ci += soil_veg_var.Ci;
                store_GPP += soil_veg_var.GPP;
                store_Rdark += soil_veg_var.Rdark;
                store_Rphoto += soil_veg_var.Rphoto;
                store_Rmaint += soil_veg_var.Rmaint;
                store_Rgrowth += soil_veg_var.Rgrowth;
                store_Raut += soil_veg_var.Raut;
                store_NPP += soil_veg_var.NPP;
            }
        }
        for (lidx = 0; lidx < options.Nlayer; lidx++) {
            store_layerevap[lidx] += step_layer[lidx].evap;
        }
        store_ppt += step_ppt;
        if (iter_aero_resist_used[0] > 0) {
            store_aero_cond_used[0] += 1 / iter_aero_resist_used[0];
        }
        else {
            store_aero_cond_used[0] += param.HUGE_RESIST;
        }
        if (iter_aero_resist_used[1] > 0) {
            store_aero_cond_used[1] += 1 / iter_aero_resist_used[1];
        }
        else {
            store_aero_cond_used[1] += param.HUGE_RESIST;
        }

        if (iveg != Nveg) {
            store_canopy_vapor_flux += step_snow.canopy_vapor_flux;
        }
        store_melt += step_melt;
        store_vapor_flux += step_snow.vapor_flux;
        store_surface_flux += step_snow.surface_flux;
        store_blowing_flux += step_snow.blowing_flux;

        out_prec[0] += step_out_prec;
        out_rain[0] += step_out_rain;
        out_snow[0] += step_out_snow;

        if (INCLUDE_SNOW) {
            /* copy needed flux terms to the snowpack */
            snow_energy.advected_sensible = soil_energy.advected_sensible;
            snow_energy.advection = soil_energy.advection;
            snow_energy.deltaCC = soil_energy.deltaCC;
            snow_energy.latent = soil_energy.latent;
            snow_energy.latent_sub = soil_energy.latent_sub;
            snow_energy.refreeze_energy = soil_energy.refreeze_energy;
            snow_energy.sensible = soil_energy.sensible;
            snow_energy.snow_flux = soil_energy.snow_flux;
        }

        store_AlbedoOver += snow_energy.AlbedoOver;
        store_AlbedoUnder += soil_energy.AlbedoUnder;
        store_AtmosLatent += soil_energy.AtmosLatent;
        store_AtmosLatentSub += soil_energy.AtmosLatentSub;
        store_AtmosSensible += soil_energy.AtmosSensible;
        store_LongOverIn += snow_energy.LongOverIn;
        store_LongUnderIn += LongUnderIn;
        store_LongUnderOut += soil_energy.LongUnderOut;
        store_NetLongAtmos += soil_energy.NetLongAtmos;
        store_NetLongOver += snow_energy.NetLongOver;
        store_NetLongUnder += soil_energy.NetLongUnder;
        store_NetShortAtmos += soil_energy.NetShortAtmos;
        store_NetShortGrnd += NetShortGrnd;
        store_NetShortOver += snow_energy.NetShortOver;
        store_NetShortUnder += soil_energy.NetShortUnder;
        store_ShortOverIn += snow_energy.ShortOverIn;
        store_ShortUnderIn += soil_energy.ShortUnderIn;
        store_canopy_advection += snow_energy.canopy_advection;
        store_canopy_latent += snow_energy.canopy_latent;
        store_canopy_latent_sub += snow_energy.canopy_latent_sub;
        store_canopy_sensible += snow_energy.canopy_sensible;
        store_canopy_refreeze += snow_energy.canopy_refreeze;
        store_deltaH += soil_energy.deltaH;
        store_fusion += soil_energy.fusion;
        store_grnd_flux += soil_energy.grnd_flux;
        store_latent += soil_energy.latent;
        store_latent_sub += soil_energy.latent_sub;
        store_melt_energy += step_melt_energy;
        store_sensible += soil_energy.sensible;
        if (step_snow.swq == 0 && INCLUDE_SNOW) {
            if (last_snow_coverage == 0 && step_prec > 0) {
                last_snow_coverage = 1;
            }
            store_advected_sensible += snow_energy.advected_sensible *
                                       last_snow_coverage;
            store_advection += snow_energy.advection * last_snow_coverage;
            store_deltaCC += snow_energy.deltaCC * last_snow_coverage;
            store_snow_flux += soil_energy.snow_flux * last_snow_coverage;
            store_refreeze_energy += snow_energy.refreeze_energy *
                                     last_snow_coverage;
        }
        else if (step_snow.snow || INCLUDE_SNOW) {
            store_advected_sensible += snow_energy.advected_sensible *
                                       (step_snow.coverage + delta_coverage);
            store_advection += snow_energy.advection *
                               (step_snow.coverage + delta_coverage);
            store_deltaCC += snow_energy.deltaCC *
                             (step_snow.coverage + delta_coverage);
            store_snow_flux += soil_energy.snow_flux *
                               (step_snow.coverage + delta_coverage);
            store_refreeze_energy += snow_energy.refreeze_energy *
                                     (step_snow.coverage + delta_coverage);
        }
        store_pot_evap += iter_pot_evap;

        /* increment time step */
        N_steps++;
        hidx += step_inc;
    }
    while (hidx < endhidx);

    /************************************************
       Store snow variables for sub-model time steps
    ************************************************/

    (*snow) = step_snow;
    snow->vapor_flux = store_vapor_flux;
    snow->blowing_flux = store_blowing_flux;
    snow->surface_flux = store_surface_flux;
    snow->canopy_vapor_flux = store_canopy_vapor_flux;
    (*Melt) = store_melt;
    snow->melt = store_melt;
    ppt = store_ppt;

    /******************************************************
       Store energy flux averages for sub-model time steps
    ******************************************************/

    (*energy) = soil_energy;
    energy->AlbedoOver = store_AlbedoOver / (double) N_steps;
    energy->AlbedoUnder = store_AlbedoUnder / (double) N_steps;
    energy->AtmosLatent = store_AtmosLatent / (double) N_steps;
    energy->AtmosLatentSub = store_AtmosLatentSub / (double) N_steps;
    energy->AtmosSensible = store_AtmosSensible / (double) N_steps;
    energy->LongOverIn = store_LongOverIn / (double) N_steps;
    energy->LongUnderIn = store_LongUnderIn / (double) N_steps;
    energy->LongUnderOut = store_LongUnderOut / (double) N_steps;
    energy->NetLongAtmos = store_NetLongAtmos / (double) N_steps;
    energy->NetLongOver = store_NetLongOver / (double) N_steps;
    energy->NetLongUnder = store_NetLongUnder / (double) N_steps;
    energy->NetShortAtmos = store_NetShortAtmos / (double) N_steps;
    energy->NetShortGrnd = store_NetShortGrnd / (double) N_steps;
    energy->NetShortOver = store_NetShortOver / (double) N_steps;
    energy->NetShortUnder = store_NetShortUnder / (double) N_steps;
    energy->ShortOverIn = store_ShortOverIn / (double) N_steps;
    energy->ShortUnderIn = store_ShortUnderIn / (double) N_steps;
    energy->advected_sensible = store_advected_sensible / (double) N_steps;
    energy->canopy_advection = store_canopy_advection / (double) N_steps;
    energy->canopy_latent = store_canopy_latent / (double) N_steps;
    energy->canopy_latent_sub = store_canopy_latent_sub / (double) N_steps;
    energy->canopy_refreeze = store_canopy_refreeze / (double) N_steps;
    energy->canopy_sensible = store_canopy_sensible / (double) N_steps;
    energy->deltaH = store_deltaH / (double) N_steps;
    energy->fusion = store_fusion / (double) N_steps;
    energy->grnd_flux = store_grnd_flux / (double) N_steps;
    energy->latent = store_latent / (double) N_steps;
    energy->latent_sub = store_latent_sub / (double) N_steps;
    energy->melt_energy = store_melt_energy / (double) N_steps;
    energy->sensible = store_sensible / (double) N_steps;
    if (snow->snow || INCLUDE_SNOW) {
        energy->advection = store_advection / (double) N_steps;
        energy->deltaCC = store_deltaCC / (double) N_steps;
        energy->refreeze_energy = store_refreeze_energy / (double) N_steps;
        energy->snow_flux = store_snow_flux / (double) N_steps;
    }
    energy->Tfoliage = snow_energy.Tfoliage;
    energy->Tfoliage_fbflag = snow_energy.Tfoliage_fbflag;
    energy->Tfoliage_fbcount = snow_energy.Tfoliage_fbcount;

    /**********************************************************
       Store vegetation variable sums for sub-model time steps
    **********************************************************/

    if (iveg != Nveg) {
        veg_var->throughfall = store_throughfall;
        veg_var->canopyevap = store_canopyevap;
        if (snow->snow) {
            veg_var->Wdew = snow_veg_var.Wdew;
        }
        else {
            veg_var->Wdew = soil_veg_var.Wdew;
        }
    }

    /**********************************************************
       Store soil layer variables for sub-model time steps
    **********************************************************/

    for (lidx = 0; lidx < Nlayers; lidx++) {
        layer[lidx] = step_layer[lidx];
        layer[lidx].evap = store_layerevap[lidx];
    }
    if (store_aero_cond_used[0] > 0 && store_aero_cond_used[0] <
        param.HUGE_RESIST) {
        aero_resist_used[0] = 1 / (store_aero_cond_used[0] / (double) N_steps);
    }
    else if (store_aero_cond_used[0] >= param.HUGE_RESIST) {
        aero_resist_used[0] = 0;
    }
    else {
        aero_resist_used[0] = param.HUGE_RESIST;
    }
    if (store_aero_cond_used[1] > 0 && store_aero_cond_used[1] <
        param.HUGE_RESIST) {
        aero_resist_used[1] = 1 / (store_aero_cond_used[1] / (double) N_steps);
    }
    else if (store_aero_cond_used[1] >= param.HUGE_RESIST) {
        aero_resist_used[1] = 0;
    }
    else {
        aero_resist_used[1] = param.HUGE_RESIST;
    }
    cell->pot_evap = store_pot_evap;

    /**********************************************************
       Store carbon cycle variable sums for sub-model time steps
    **********************************************************/

    if (options.CARBON && iveg != Nveg) {
        veg_var->rc = 1 / store_gc / (double) N_steps;
        for (cidx = 0; cidx < options.Ncanopy; cidx++) {
            veg_var->rsLayer[cidx] = 1 / store_gsLayer[cidx] / (double) N_steps;
        }
        veg_var->Ci = store_Ci / (double) N_steps;
        veg_var->GPP = store_GPP / (double) N_steps;
        veg_var->Rdark = store_Rdark / (double) N_steps;
        veg_var->Rphoto = store_Rphoto / (double) N_steps;
        veg_var->Rmaint = store_Rmaint / (double) N_steps;
        veg_var->Rgrowth = store_Rgrowth / (double) N_steps;
        veg_var->Raut = store_Raut / (double) N_steps;
        veg_var->NPP = store_NPP / (double) N_steps;

        free((char *) (store_gsLayer));

        soil_carbon_balance(soil_con, energy, cell, veg_var);

        // Update running total annual NPP
        if (veg_var->NPP > 0) {
            veg_var->AnnualNPP += veg_var->NPP * CONST_MWC / MOLE_PER_KMOLE *
                                  gp->dt;
        }
    }

    /********************************************************
       Compute Runoff, Baseflow, and Soil Moisture Transport
    ********************************************************/

    (*inflow) = ppt;

    ErrorFlag = runoff(cell, energy, soil_con, ppt, soil_con->frost_fract,
                       options.Nnode);

    return(ErrorFlag);
}