int update_thermal_nodes(all_vars_struct     *all_vars,
			 int                  Nveg,
			 int                  Nnodes,
			 soil_con_struct     *soil_con,
			 veg_con_struct      *veg_con)
/**********************************************************************
  update_thermal_nodes           Jennifer Adam        August 16, 2007

  This routine is run after subsidence occurs (used only for EXCESS_ICE option).
  This routine updates the node depths and interpolates the current
  node temperatures to the new depths, then recalculates the nodal
  thermal properties.  Much of this routine is taken directly from
  initialize_model_state.

  Modifications:
  2009-Feb-09 Removed dz_node from call to
	      distribute_node_moisture_properties.			KAC via TJB
  2009-Feb-09 Removed dz_node from call to find_0_degree_front.		KAC via TJB
  2012-Jan-16 Removed LINK_DEBUG code					BN
  2013-Dec-26 Removed EXCESS_ICE option.				TJB
**********************************************************************/
{
  extern option_struct options;
  extern veg_lib_struct *veg_lib;
  char     ErrStr[MAXSTRING];
  char     FIRST_VEG;
  int      veg, index;
  int      lidx;
  int      band;
  int      ErrorFlag;
  double   Cv;
  double   Zsum, dp;
  double   tmpdp, tmpadj, Bexp;
  double   moist[MAX_VEG][MAX_BANDS][MAX_LAYERS];

  cell_data_struct      **cell;
  energy_bal_struct     **energy;

  double Tnode_prior[MAX_NODES];
  double Zsum_prior[MAX_NODES];

  cell    = all_vars->cell;
  energy  = all_vars->energy;
  
  dp = soil_con->dp;

  FIRST_VEG = TRUE;

  /*****************************************************************
    Update soil thermal node depths, thicknesses, and temperatures.
    CASE 3: Initialize Energy Balance Variables if not using quick
    ground heat flux, and no Initial Condition File Given 
  *****************************************************************/

  /*****************************************************************
    Update soil thermal node depths and thicknesses.
  *****************************************************************/
  //set previous Zsum
  for ( index = 0; index < Nnodes; index++ ) 
    Zsum_prior[index] = soil_con->Zsum_node[index];

  if(!options.EXP_TRANS){  
    /* Nodes set at surface, the depth of the first layer,
       twice the depth of the first layer, and at the
       damping depth.  Extra nodes are placed equal distance
       between the damping depth and twice the depth of the
       first layer. */
    
    soil_con->dz_node[0] = soil_con->depth[0];
    soil_con->dz_node[1] = soil_con->depth[0];
    soil_con->dz_node[2] = soil_con->depth[0];	  
    soil_con->Zsum_node[0] = 0;
    soil_con->Zsum_node[1] = soil_con[0].depth[0];
    Zsum   = 2. * soil_con[0].depth[0];
    soil_con->Zsum_node[2] = Zsum;
    tmpdp  = dp - soil_con[0].depth[0] * 2.5;
    tmpadj = 3.5;
    for ( index = 3; index < Nnodes-1; index++ ) {
      soil_con->dz_node[index] = tmpdp/(((double)Nnodes-tmpadj));
      Zsum += (soil_con->dz_node[index]
	       +soil_con->dz_node[index-1])/2.;
      soil_con->Zsum_node[index] = Zsum;
    }
    soil_con->dz_node[Nnodes-1] = (dp - Zsum 
				   - soil_con->dz_node[Nnodes-2] 
				   / 2. ) * 2.;
    Zsum += (soil_con->dz_node[Nnodes-2]
	     +soil_con->dz_node[Nnodes-1])/2.;
    soil_con->Zsum_node[Nnodes-1] = Zsum;
    if((int)(Zsum*1000+0.5) != (int)(dp*1000+0.5)) {
      sprintf(ErrStr,"Sum of thermal node thicknesses (%f) in initialize_model_state do not equal dp (%f), check initialization procedure",Zsum,dp);
      nrerror(ErrStr);
    }
  }
  else{ /* exponential grid transformation, EXP_TRANS = TRUE*/
    
    /*calculate exponential function parameter */
    Bexp = logf(dp+1.)/(double)(Nnodes-1); //to force Zsum=dp at bottom node
    for ( index = 0; index <= Nnodes-1; index++ )
      soil_con->Zsum_node[index] = expf(Bexp*index)-1.;
    
    //top node	  
    index=0;
    soil_con->dz_node[index] = soil_con->Zsum_node[index+1]-soil_con->Zsum_node[index];
    //middle nodes
    for ( index = 1; index < Nnodes-1; index++ ) {
      soil_con->dz_node[index] = (soil_con->Zsum_node[index+1]-soil_con->Zsum_node[index])/2.+(soil_con->Zsum_node[index]-soil_con->Zsum_node[index-1])/2.;
    }
    //bottom node
    index=Nnodes-1;
    soil_con->dz_node[index] = soil_con->Zsum_node[index]-soil_con->Zsum_node[index-1];
  }
#if VERBOSE
  fprintf(stderr,"More updated parameters in soil_con: dz_node and Zsum_node.\n");
#endif

  /******************************************
    Update soil thermal node temperatures via linear interpolation.
  ******************************************/
  for ( veg = 0 ; veg <= Nveg ; veg++ ) {
    // Initialize soil for existing vegetation types
    Cv = veg_con[veg].Cv;
    
    if ( Cv > 0 ) {
      for( band = 0; band < options.SNOW_BAND; band++ ) {
	if ( soil_con->AreaFract[band] > 0. ) {
	  //set previous temperatures
	  for ( index = 0; index < Nnodes; index++ ) 
	    Tnode_prior[index] = energy[veg][band].T[index];
	  //top node: no need to update surface temperature
	  //remaining nodes
	  for ( index = 1; index < Nnodes; index++ ) {
	    energy[veg][band].T[index] = linear_interp(soil_con->Zsum_node[index],Zsum_prior[index-1],Zsum_prior[index],Tnode_prior[index-1],Tnode_prior[index]);	
	  }//node
	}	
      }//band
    }
  }//veg

  /******************************************
    Update soil thermal node properties 
  ******************************************/  
  FIRST_VEG = TRUE;
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    // Initialize soil for existing vegetation types
    Cv = veg_con[veg].Cv;

    if ( Cv > 0 ) {
      for( band = 0; band < options.SNOW_BAND; band++ ) {
	// Initialize soil for existing snow elevation bands
	if ( soil_con->AreaFract[band] > 0. ) {
	  /** Set soil properties for all soil nodes **/
	  if(FIRST_VEG) {
	    FIRST_VEG = FALSE;
	    set_node_parameters(soil_con->dz_node, soil_con->Zsum_node, soil_con->max_moist_node,
				  soil_con->expt_node, soil_con->bubble_node,
				  soil_con->alpha, soil_con->beta,
				  soil_con->gamma, soil_con->depth,
				  soil_con->max_moist, soil_con->expt, 
				  soil_con->bubble, soil_con->quartz, 
				  Nnodes, options.Nlayer, soil_con->FS_ACTIVE);	  
	  }

	  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) 
	    moist[veg][band][lidx] = cell[veg][band].layer[lidx].moist;

	  /* set soil moisture properties for all soil thermal nodes */
	  if ( !( options.LAKES && veg_con->LAKE != 0 ) ) {
	    ErrorFlag = distribute_node_moisture_properties(energy[veg][band].moist,
						  energy[veg][band].ice,
						  energy[veg][band].kappa_node,
						  energy[veg][band].Cs_node,
						  soil_con->Zsum_node,
						  energy[veg][band].T,
						  soil_con->max_moist_node,
						  soil_con->expt_node,
						  soil_con->bubble_node,
						  moist[veg][band],
						  soil_con->depth,
						  soil_con->soil_dens_min,
						  soil_con->bulk_dens_min,
						  soil_con->quartz,
						  soil_con->soil_density,
						  soil_con->bulk_density,
						  soil_con->organic,
						  Nnodes, options.Nlayer,
						  soil_con->FS_ACTIVE);
	    if ( ErrorFlag == ERROR ) return ( ErrorFlag );
	  }

	  /* initialize layer moistures and ice contents */
	  if ( !( options.LAKES && veg_con->LAKE != 0 ) ) {
            if (options.QUICK_FLUX) {
              ErrorFlag = estimate_layer_ice_content_quick_flux(cell[veg][band].layer,
					 soil_con->depth, soil_con->dp,
					 energy[veg][band].T[0], energy[veg][band].T[1],
					 soil_con->avg_temp, soil_con->max_moist, 
					 soil_con->expt, soil_con->bubble, 
					 soil_con->frost_fract, soil_con->frost_slope, 
					 soil_con->FS_ACTIVE);
            }
            else {
	      ErrorFlag = estimate_layer_ice_content(cell[veg][band].layer,
						     soil_con->Zsum_node,
						     energy[veg][band].T,
						     soil_con->max_moist_node,
						     soil_con->expt_node,
						     soil_con->bubble_node,
						     soil_con->depth,
						     soil_con->max_moist,
						     soil_con->expt,
						     soil_con->bubble,
						     soil_con->frost_fract, 
						     soil_con->frost_slope, 
						     Nnodes, options.Nlayer, 
						     soil_con->FS_ACTIVE);	      
	    }
	  }
	    
	  /* Find freezing and thawing front depths */
	  if(!options.QUICK_FLUX && soil_con->FS_ACTIVE) 
	    if ( !( options.LAKES && veg_con->LAKE != 0 ) ) 
	      find_0_degree_fronts(&energy[veg][band], soil_con->Zsum_node, energy[veg][band].T, Nnodes);
	}
      }//band
    }
  }//veg	

  return(0);  
}
int initialize_model_state(all_vars_struct     *all_vars,
			   all_vars_struct     *all_vars_crop,
			   dmy_struct           dmy,
			   global_param_struct *global_param,
			   filep_struct         filep,
			   int                  cellnum,
			   int                  Nveg,
			   int                  Nnodes,
			   double               surf_temp, 
			   soil_con_struct     *soil_con,
			   veg_con_struct      *veg_con,
			   lake_con_struct      lake_con)
/**********************************************************************
  initialize_model_state      Keith Cherkauer	    April 17, 2000

  This routine initializes the model state (energy balance, water balance,
  and snow components).  If a state file is provided to the model than its
  contents are checked to see if it agrees with the current simulation
  set-up, if so it is used to initialize the model state.  If no state
  file is provided the model initializes all variables with defaults and
  the user should expect to throw out the beginning of the simulation 
  period as model start-up.

  UNITS: (m, s, kg, C, moisture in mm) unless otherwise specified

  Modifications:
  4-17-00 Modified from initialize_energy_bal.c and initialize_snow.c
          to provide a single controlling routine for initializing the
          model state.
  9-00    Fixed bug where initialization of soil node temperatures 
          and moitures was within two vegetation loops, thus only
          the first vegetation type was properly initialized.     KAC
  2-19-03 Modified to initialize soil and vegetation parameters for
          the dry grid cell fraction, if distributed precipitation
          is activated.                                           KAC
  11-18-02 Modified to initialize lake and wetland algorithms 
          variables.                                              LCB
  2-10-03 Fixed looping problem with initialization of soil moisture. KAC
  3-12-03 Modified so that soil layer ice content is only calculated 
          when frozen soil is implemented and active in the current 
          grid cell.                                                KAC
  04-10-03 Modified to read storm parameters from model state file.  KAC
  04-25-03 Modified to work with vegetation type specific storm 
           parameters.                                              KAC
  07-May-04 Initialize soil_con->dz_node[Nnodes] to 0.0, since it is
	    accessed in set_node_parameters().				TJB
  01-Nov-04 Added support for state files containing SPATIAL_FROST
	    and LAKE_MODEL state variables.				TJB
  2006-Apr-21 Replaced Cv (uninitialized) with lake_con.Cl[0] in
	      surfstor calculation.					TJB
  2006-Sep-23 Implemented flexible output configuration; uses the new
              save_data structure to track changes in moisture storage
              over each time step; this needs initialization here.	TJB
  2006-Oct-10 Added snow[veg][band].snow_canopy to save_data.swe.	TJB
  2006-Oct-16 Merged infiles and outfiles structs into filep_struct;
	      This included removing the unused init_snow file.		TJB
  2006-Nov-07 Removed LAKE_MODEL option.				TJB
  2007-Apr-24 Added EXP_TRANS option.					JCA
  2007-Apr-24 Zsum_node loaded into soil_con structure for later use
	      without having to recalculate.				JCA
  2007-Aug-09 Added features for EXCESS_ICE option.			JCA
  2007-Aug-21 Return value of ErrorFlag if error in
	      distribute_node_moisture_properties.			JCA
  2007-Sep-18 Check for soil moist exceeding max moist moved from
	      read_initial_model_state to here.				JCA
  2007-Oct-24 Modified initialize_lake() to return ErrorFlag.		TJB
  2008-Mar-01 Reinserted missing logic for QUICK_FS in calls to
	      distribute_node_moisture_properties() and
	      estimate_layer_ice_content().				TJB
  2009-Feb-09 Removed dz_node from call to
	      distribute_node_moisture_properties.			KAC via TJB
  2009-Feb-09 Removed dz_node from call to find_0_degree_front.		KAC via TJB
  2009-Mar-15 Modified to not call estimate_layer_ice_content() if
	      not modeling frozen soil.					KAC via TJB
  2009-Mar-16 Added resid_moist to argument list of
	      estimate_layer_ice_content().  This allows computation
	      of min_liq, the minimum allowable liquid water content
	      in each layer as a function of temperature.		TJB
  2009-Jun-09 Modified to use extension of veg_lib structure to contain
	      bare soil information.					TJB
  2009-Jul-26 Added initial estimate of incoming longwave at surface
	      (LongUnderOut) for use in canopy snow T iteration.	TJB
  2009-Jul-31 Removed extra lake/wetland veg tile.			TJB
  2009-Sep-19 Added T fbcount to count TFALLBACK occurrences.		TJB
  2009-Sep-19 Made initialization of Tfoliage more accurate for snow bands.	TJB
  2009-Sep-28 Added initialization of energy structure.			TJB
  2009-Nov-15 Added check to ensure that depth of first thermal node
	      is <= depth of first soil layer.				TJB
  2009-Dec-11 Removed initialization of save_data structure, since this
	      is now performed by the initial call to put_data().	TJB
  2009-Dec-11 Removed min_liq and options.MIN_LIQ.			TJB
  2010-Nov-11 Updated call to initialize_lake() to accommodate new
	      skip_hydro flag.						TJB
  2011-Mar-01 Updated calls to initialize_soil() and initialize_lake()
	      to accommodate new arguments.  Added more detailed validation
	      of soil moisture.						TJB
  2011-Mar-05 Added validation of initial soil moisture, ice, and snow
	      variables to make sure they are self-consistent.		TJB
  2011-May-31 Removed options.GRND_FLUX.  Now soil temperatures and 
	      ground flux are always computed.				TJB
  2011-Jun-03 Added options.ORGANIC_FRACT.  Soil properties now take
	      organic fraction into account.				TJB
  2011-Jul-05 Changed logic initializing soil temperatures so that
	      type of initialization depends solely on options.QUICK_FLUX;
	      options.Nnodes is no longer automatically reset here.	TJB
  2012-Jan-16 Removed LINK_DEBUG code					BN
  2012-Jan-28 Added stability check for case of (FROZEN_SOIL=TRUE &&
	      IMPLICIT=FALSE).						TJB
  2013-Jul-25 Fixed incorrect condition on lake initialization.		TJB
  2013-Jul-25 Moved computation of tmp_moist argument of
	      compute_runoff_and_asat() so that it would always be
	      initialized.						TJB
  2013-Dec-26 Removed EXCESS_ICE option.						TJB
  2013-Dec-27 Moved SPATIAL_FROST to options_struct.			TJB
  2013-Dec-27 Removed QUICK_FS option.							TJB
  2014-Jan-13 Added validation of Nnodes and dp for EXP_TRANS=TRUE.	TJB
  2014-Feb-09 Made non-spinup initial temperatures more consistent with
	      annual average air temperature and bottom boundary
	      temperature.											TJB
  2014-Mar-28 Removed DIST_PRCP option.							TJB
**********************************************************************/
{
  extern option_struct options;
  extern veg_lib_struct *veg_lib;

  char     ErrStr[MAXSTRING];
  char     FIRST_VEG;
  int      i, j, ii, veg, index;
  int      idx;
  int      cidx;
  int      lidx;
  int      nidx;
  double   tmp_moist[MAX_LAYERS];
  double   tmp_runoff;
  int      band;
  int      frost_area;
  int      ErrorFlag;
  double   Cv;
  double   Zsum, dp;
  double   tmpdp, tmpadj, Bexp;
  double   Tair;
  double   tmp;
  double  *M;
  double   moist[MAX_VEG][MAX_BANDS][MAX_LAYERS];
  double   ice[MAX_VEG][MAX_BANDS][MAX_LAYERS][MAX_FROST_AREAS];
  double   Clake;
  double   surf_swq;
  double   pack_swq;
  double   TreeAdjustFactor[MAX_BANDS];
  double dt_thresh;
  int tmp_lake_idx;

  cell_data_struct      **cell;
  energy_bal_struct     **energy;
  lake_var_struct        *lake_var;
  snow_data_struct      **snow;
  veg_var_struct        **veg_var;

  cell    = all_vars->cell;
  energy  = all_vars->energy;
  lake_var = &all_vars->lake_var;
  snow    = all_vars->snow;
  veg_var = all_vars->veg_var;

  // Initialize soil depths
  dp = soil_con->dp;

  FIRST_VEG = TRUE;

  // increase initial soil surface temperature if air is very cold
  Tair = surf_temp;
  if ( surf_temp < -1. ) surf_temp = -1.;
  
  /********************************************
    Initialize all snow pack variables 
    - some may be reset if state file present
  ********************************************/

  initialize_snow(snow, Nveg, cellnum);

  /********************************************
    Initialize all soil layer variables 
    - some may be reset if state file present
  ********************************************/

  initialize_soil(cell, soil_con, veg_con, Nveg);

  /********************************************
    Initialize all vegetation variables 
    - some may be reset if state file present
  ********************************************/

  initialize_veg(veg_var, veg_con, global_param, Nveg);

  /********************************************
    Initialize all lake variables 
  ********************************************/

  if ( options.LAKES ) {
    tmp_lake_idx = lake_con.lake_idx;
    if (tmp_lake_idx < 0) tmp_lake_idx = 0;
    ErrorFlag = initialize_lake(lake_var, lake_con, soil_con, &(cell[tmp_lake_idx][0]), surf_temp, 0);
    if (ErrorFlag == ERROR) return(ErrorFlag);
  }

  /********************************************
    Initialize all spatial frost variables 
  ********************************************/

  for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ ) {
    if ( options.Nfrost == 1 ) soil_con->frost_fract[frost_area] = 1.;
    else if (options.Nfrost == 2 ) soil_con->frost_fract[frost_area] = 0.5;
    else {
      soil_con->frost_fract[frost_area] = 1. / (options.Nfrost - 1);
      if ( frost_area == 0 || frost_area == options.Nfrost-1 ) 
	soil_con->frost_fract[frost_area] /= 2.;
    }
  }

  /********************************************************
    Compute grid cell fractions for all subareas used in 
    spatial distribution of soil frost routines.
  ********************************************************/

  /************************************************************************
    CASE 1: Not using quick ground heat flux, and initial conditions files 
    provided
  ************************************************************************/

  if(options.INIT_STATE) {

    read_initial_model_state(filep.init_state, all_vars, global_param,  
			     Nveg, options.SNOW_BAND, cellnum, soil_con,
			     lake_con);

    /******Check that soil moisture does not exceed maximum allowed************/
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      for( band = 0; band < options.SNOW_BAND; band++ ) {
        for( lidx = 0; lidx < options.Nlayer; lidx++ ) {	  

	  if ( cell[veg][band].layer[lidx].moist > soil_con->max_moist[lidx] ) {
            fprintf( stderr, "WARNING: Initial soil moisture (%f mm) exceeds maximum (%f mm) in layer %d for veg tile %d and snow band%d.  Resetting to maximum.\n", cell[veg][band].layer[lidx].moist, soil_con->max_moist[lidx], lidx, veg, band );
            for ( frost_area = 0; frost_area < options.Nfrost; frost_area++)
              cell[veg][band].layer[lidx].ice[frost_area] *= soil_con->max_moist[lidx]/cell[veg][band].layer[lidx].moist;
            cell[veg][band].layer[lidx].moist = soil_con->max_moist[lidx];
	  }

          for ( frost_area = 0; frost_area < options.Nfrost; frost_area++) {
            if (cell[veg][band].layer[lidx].ice[frost_area] > cell[veg][band].layer[lidx].moist)
              cell[veg][band].layer[lidx].ice[frost_area] = cell[veg][band].layer[lidx].moist;
          }
          tmp_moist[lidx] = cell[veg][band].layer[lidx].moist;

	}
        compute_runoff_and_asat(soil_con, tmp_moist, 0, &(cell[veg][band].asat), &tmp_runoff);
      }

      // Override possible bad values of soil moisture under lake coming from state file
      // (ideally we wouldn't store these in the state file in the first place)
      if (options.LAKES && veg == lake_con.lake_idx) {
        for( lidx = 0; lidx < options.Nlayer; lidx++ ) {
          lake_var->soil.layer[lidx].moist = soil_con->max_moist[lidx];
          for ( frost_area = 0; frost_area < options.Nfrost; frost_area++) {
            if (lake_var->soil.layer[lidx].ice[frost_area] > lake_var->soil.layer[lidx].moist)
              lake_var->soil.layer[lidx].ice[frost_area] = lake_var->soil.layer[lidx].moist;
          }
        }
      }
    }


    /****** initialize moist and ice ************/
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;
      
      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {
	  for( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    moist[veg][band][lidx] = cell[veg][band].layer[lidx].moist;

	    for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ )
	      ice[veg][band][lidx][frost_area] = cell[veg][band].layer[lidx].ice[frost_area];
	  }
	}
      }
    }

    /******Check that snow pack terms are self-consistent************/
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      for ( band = 0 ; band < options.SNOW_BAND ; band++ ) {
        if (snow[veg][band].swq > MAX_SURFACE_SWE) {
          pack_swq = snow[veg][band].swq-MAX_SURFACE_SWE;
          surf_swq = MAX_SURFACE_SWE;
        }
        else {
          pack_swq = 0;
          surf_swq = snow[veg][band].swq;
          snow[veg][band].pack_temp = 0;
        }
        if (snow[veg][band].surf_water > LIQUID_WATER_CAPACITY*surf_swq) {
          snow[veg][band].pack_water += snow[veg][band].surf_water - (LIQUID_WATER_CAPACITY*surf_swq);
          snow[veg][band].surf_water = LIQUID_WATER_CAPACITY*surf_swq;
        }
        if (snow[veg][band].pack_water > LIQUID_WATER_CAPACITY*pack_swq) {
          snow[veg][band].pack_water = LIQUID_WATER_CAPACITY*pack_swq;
        }
      }
    }

  }
  
  /************************************************************************
    CASE 2: Initialize soil if using quick heat flux, and no initial
    soil properties file given
  ************************************************************************/
    
  else if(options.QUICK_FLUX) {
    Nnodes = options.Nnode;

    /* Initialize soil node thicknesses */
    soil_con->dz_node[0]   = soil_con->depth[0];
    soil_con->dz_node[1]   = soil_con->depth[0];
    soil_con->dz_node[2]   = 2. * (dp - 1.5 * soil_con->depth[0]);    
    soil_con->Zsum_node[0] = 0;
    soil_con->Zsum_node[1] = soil_con->depth[0];
    soil_con->Zsum_node[2] = dp;

    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;
      
      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {

	  /* Initialize soil node temperatures */
	  energy[veg][band].T[0] = surf_temp;
	  energy[veg][band].T[1] = surf_temp;
	  energy[veg][band].T[2] = soil_con->avg_temp;

	  /* Initialize soil layer moisture and ice contents */
	  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    moist[veg][band][lidx] = cell[veg][band].layer[lidx].moist;
	    for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ )
	      ice[veg][band][lidx][frost_area] = 0.;
	  }
	}
      }
    }
  }

  /*****************************************************************
    CASE 3: Initialize Energy Balance Variables if not using quick
    ground heat flux, and no Initial Condition File Given 
  *****************************************************************/
  else if(!options.QUICK_FLUX) {
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;
      
      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {
	  
	  if(!options.EXP_TRANS){  
	    /* Initialize soil node temperatures and thicknesses 
	       Nodes set at surface, the depth of the first layer,
	       twice the depth of the first layer, and at the
	       damping depth.  Extra nodes are placed equal distance
	       between the damping depth and twice the depth of the
	       first layer. */
	    
	    soil_con->dz_node[0] = soil_con->depth[0];
	    soil_con->dz_node[1] = soil_con->depth[0];
	    soil_con->dz_node[2] = soil_con->depth[0];

	    soil_con->Zsum_node[0] = 0;
	    soil_con->Zsum_node[1] = soil_con[0].depth[0];
	    Zsum   = 2. * soil_con[0].depth[0];
	    soil_con->Zsum_node[2] = Zsum;
	    tmpdp  = dp - soil_con[0].depth[0] * 2.5;
	    tmpadj = 3.5;
	    for ( index = 3; index < Nnodes-1; index++ ) {
	      if ( FIRST_VEG ) {
		soil_con->dz_node[index] = tmpdp/(((double)Nnodes-tmpadj));
	      }
	      Zsum += (soil_con->dz_node[index]
		       +soil_con->dz_node[index-1])/2.;
	      soil_con->Zsum_node[index] = Zsum;
	    }
	    energy[veg][band].T[0] = surf_temp;
	    for ( index = 1; index < Nnodes; index++ ) {
	      energy[veg][band].T[index] = soil_con->avg_temp;
	    }
	    if ( FIRST_VEG ) {
	      FIRST_VEG = FALSE;
	      soil_con->dz_node[Nnodes-1] = (dp - Zsum 
					     - soil_con->dz_node[Nnodes-2] 
					     / 2. ) * 2.;
	      Zsum += (soil_con->dz_node[Nnodes-2]
		       +soil_con->dz_node[Nnodes-1])/2.;
	      soil_con->Zsum_node[Nnodes-1] = Zsum;
	      if((int)(Zsum*1000+0.5) != (int)(dp*1000+0.5)) {
		sprintf(ErrStr,"Sum of thermal node thicknesses (%f) in initialize_model_state do not equal dp (%f), check initialization procedure",Zsum,dp);
		nrerror(ErrStr);
	      }
	    }
	  }
	  else{ /* exponential grid transformation, EXP_TRANS = TRUE*/
	    
	    /*calculate exponential function parameter */
	    if ( FIRST_VEG ) {
	      Bexp = logf(dp+1.)/(double)(Nnodes-1); //to force Zsum=dp at bottom node
              /* validate Nnodes by requiring that there be at least 3 nodes in the top 50cm */
              if (Nnodes < 5*logf(dp+1.)+1) {
		sprintf(ErrStr,"The number of soil thermal nodes (%d) is too small for the supplied damping depth (%f) with EXP_TRANS set to TRUE, leading to fewer than 3 nodes in the top 50 cm of the soil column.  For EXP_TRANS=TRUE, Nnodes and dp must follow the relationship:\n5*ln(dp+1)<Nnodes-1\nEither set Nnodes to at least %d in the global param file or reduce damping depth to %f in the soil parameter file.  Or set EXP_TRANS to FALSE in the global parameter file.",Nnodes,dp,(int)(5*logf(dp+1.))+2,exp(0.2*(Nnodes-1))+1);
                nrerror(ErrStr);
              }
	      for ( index = 0; index <= Nnodes-1; index++ )
		soil_con->Zsum_node[index] = expf(Bexp*index)-1.;
	      if(soil_con->Zsum_node[0] > soil_con->depth[0]) {
		sprintf(ErrStr,"Depth of first thermal node (%f) in initialize_model_state is greater than depth of first soil layer (%f); increase the number of nodes or decrease the thermal damping depth dp (%f)",soil_con->Zsum_node[0],soil_con->depth[0],dp);
		nrerror(ErrStr);
	      }
	    }	    
	    
	    //top node	  
	    index=0;
	    if ( FIRST_VEG )
	      soil_con->dz_node[index] = soil_con->Zsum_node[index+1]-soil_con->Zsum_node[index];
	    energy[veg][band].T[index] = surf_temp;
	    //middle nodes
	    for ( index = 1; index < Nnodes-1; index++ ) {
	      if ( FIRST_VEG ) {
		soil_con->dz_node[index] = (soil_con->Zsum_node[index+1]-soil_con->Zsum_node[index])/2.+(soil_con->Zsum_node[index]-soil_con->Zsum_node[index-1])/2.;
	      }
//	      energy[veg][band].T[index] = exp_interp(soil_con->Zsum_node[index],0.,soil_con[0].dp,
//						      surf_temp,soil_con[0].avg_temp);
              energy[veg][band].T[index] = soil_con->avg_temp;
	    }
	    //bottom node
	    index=Nnodes-1;
	    if ( FIRST_VEG )
	      soil_con->dz_node[index] = soil_con->Zsum_node[index]-soil_con->Zsum_node[index-1];
	    energy[veg][band].T[index] = soil_con->avg_temp;

	  } // end if !EXP_TRANS
	  
	  //initialize moisture and ice for each soil layer
	  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    moist[veg][band][lidx] = cell[veg][band].layer[lidx].moist;
	    for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ )
	      ice[veg][band][lidx][frost_area] = 0.;
	  }
	}
      }
    }
  }

  /*********************************
    CASE 4: Unknown option
  *********************************/
  else {
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;

      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {
	  // Initialize soil for existing snow elevation bands
	  if ( soil_con->AreaFract[band] > 0. ) {	  
	    for ( index = 0; index < options.Nlayer; index++ ) {
	      soil_con->dz_node[index] = 1.;
	    }
	  }
	}
      }
    }
  }

  /******************************************
    Initialize soil thermal node properties 
  ******************************************/

  FIRST_VEG = TRUE;
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    // Initialize soil for existing vegetation types
    Cv = veg_con[veg].Cv;

    if ( Cv > 0 ) {
      for( band = 0; band < options.SNOW_BAND; band++ ) {
	// Initialize soil for existing snow elevation bands
	if ( soil_con->AreaFract[band] > 0. ) {
	    
	  /** Set soil properties for all soil nodes **/
	  if(FIRST_VEG) {
	    FIRST_VEG = FALSE;
	    set_node_parameters(soil_con->dz_node, soil_con->Zsum_node, soil_con->max_moist_node,
				soil_con->expt_node, soil_con->bubble_node,
				soil_con->alpha, soil_con->beta,
				soil_con->gamma, soil_con->depth,
				soil_con->max_moist, soil_con->expt, 
				soil_con->bubble, soil_con->quartz, 
				Nnodes, options.Nlayer, soil_con->FS_ACTIVE);	  
	  }
	
	  /* set soil moisture properties for all soil thermal nodes */
	  ErrorFlag = distribute_node_moisture_properties(energy[veg][band].moist,
						energy[veg][band].ice,
						energy[veg][band].kappa_node,
						energy[veg][band].Cs_node,
						soil_con->Zsum_node,
						energy[veg][band].T,
						soil_con->max_moist_node,
						soil_con->expt_node,
						soil_con->bubble_node,
						moist[veg][band], 
						soil_con->depth,
						soil_con->soil_dens_min,
						soil_con->bulk_dens_min,
						soil_con->quartz,
						soil_con->soil_density,
						soil_con->bulk_density,
						soil_con->organic,
						Nnodes, options.Nlayer,
						soil_con->FS_ACTIVE);
	  if ( ErrorFlag == ERROR ) return ( ErrorFlag );

          /* Check node spacing v time step */
          /* (note this is only approximate since heat capacity and conductivity can change considerably during the simulation depending on soil moisture and ice content) */
          if ((options.FROZEN_SOIL && !options.QUICK_FLUX) && !options.IMPLICIT) {
            dt_thresh = 0.5*energy[veg][band].Cs_node[1]/energy[veg][band].kappa_node[1]*pow((soil_con->dz_node[1]),2)/3600; // in hours
            if (global_param->dt > dt_thresh) {
              sprintf(ErrStr,"ERROR: You are currently running FROZEN SOIL with an explicit method (IMPLICIT is set to FALSE).  For the explicit method to be stable, time step %d hours is too large for the given thermal node spacing %f m, soil heat capacity %f J/m3/K, and soil thermal conductivity %f J/m/s/K.  Either set IMPLICIT to TRUE in your global parameter file (this is the recommended action), or decrease time step length to <= %f hours, or decrease the number of soil thermal nodes.",global_param->dt,soil_con->dz_node[1],energy[veg][band].Cs_node[1],energy[veg][band].kappa_node[1],dt_thresh);
              nrerror(ErrStr);
            }
          }

	  /* initialize layer moistures and ice contents */
	  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    cell[veg][band].layer[lidx].moist = moist[veg][band][lidx];
	    for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ )
              cell[veg][band].layer[lidx].ice[frost_area] = ice[veg][band][lidx][frost_area];
	  }
          if (options.QUICK_FLUX) {
            ErrorFlag = estimate_layer_ice_content_quick_flux(cell[veg][band].layer,
					 soil_con->depth, soil_con->dp,
					 energy[veg][band].T[0], energy[veg][band].T[1],
					 soil_con->avg_temp, soil_con->max_moist, 
					 soil_con->expt, soil_con->bubble, 
					 soil_con->frost_fract, soil_con->frost_slope, 
					 soil_con->FS_ACTIVE);
          }
          else {
	    ErrorFlag = estimate_layer_ice_content(cell[veg][band].layer,
						     soil_con->Zsum_node,
						     energy[veg][band].T,
						     soil_con->max_moist_node,
						     soil_con->expt_node,
						     soil_con->bubble_node,
						     soil_con->depth,
						     soil_con->max_moist,
						     soil_con->expt,
						     soil_con->bubble,
						     soil_con->frost_fract, 
						     soil_con->frost_slope, 
						     Nnodes, options.Nlayer, 
						     soil_con->FS_ACTIVE);
          }

	  /* Find freezing and thawing front depths */
	  if(!options.QUICK_FLUX && soil_con->FS_ACTIVE) 
	    find_0_degree_fronts(&energy[veg][band], soil_con->Zsum_node, energy[veg][band].T, Nnodes);
	}
      }
    }
  }	

  // initialize miscellaneous energy balance terms
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    for ( band = 0; band < options.SNOW_BAND; band++ ) {
      /* Set fluxes to 0 */
      energy[veg][band].advected_sensible = 0.0;
      energy[veg][band].advection         = 0.0;
      energy[veg][band].AtmosError        = 0.0;
      energy[veg][band].AtmosLatent       = 0.0;
      energy[veg][band].AtmosLatentSub    = 0.0;
      energy[veg][band].AtmosSensible     = 0.0;
      energy[veg][band].canopy_advection  = 0.0;
      energy[veg][band].canopy_latent     = 0.0;
      energy[veg][band].canopy_latent_sub = 0.0;
      energy[veg][band].canopy_refreeze   = 0.0;
      energy[veg][band].canopy_sensible   = 0.0;
      energy[veg][band].deltaCC           = 0.0;
      energy[veg][band].deltaH            = 0.0;
      energy[veg][band].error             = 0.0;
      energy[veg][band].fusion            = 0.0;
      energy[veg][band].grnd_flux         = 0.0;
      energy[veg][band].latent            = 0.0;
      energy[veg][band].latent_sub        = 0.0;
      energy[veg][band].longwave          = 0.0;
      energy[veg][band].LongOverIn        = 0.0;
      energy[veg][band].LongUnderIn       = 0.0;
      energy[veg][band].LongUnderOut      = 0.0;
      energy[veg][band].melt_energy       = 0.0;
      energy[veg][band].NetLongAtmos      = 0.0;
      energy[veg][band].NetLongOver       = 0.0;
      energy[veg][band].NetLongUnder      = 0.0;
      energy[veg][band].NetShortAtmos     = 0.0;
      energy[veg][band].NetShortGrnd      = 0.0;
      energy[veg][band].NetShortOver      = 0.0;
      energy[veg][band].NetShortUnder     = 0.0;
      energy[veg][band].out_long_canopy   = 0.0;
      energy[veg][band].out_long_surface  = 0.0;
      energy[veg][band].refreeze_energy   = 0.0;
      energy[veg][band].sensible          = 0.0;
      energy[veg][band].shortwave         = 0.0;
      energy[veg][band].ShortOverIn       = 0.0;
      energy[veg][band].ShortUnderIn      = 0.0;
      energy[veg][band].snow_flux         = 0.0;
      /* Initial estimate of LongUnderOut for use by snow_intercept() */
      tmp = energy[veg][band].T[0] + KELVIN;
      energy[veg][band].LongUnderOut = STEFAN_B * tmp * tmp * tmp * tmp;
      energy[veg][band].Tfoliage     = Tair + soil_con->Tfactor[band];
    }
  }

  // initialize Tfallback counters
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    for ( band = 0; band < options.SNOW_BAND; band++ ) {
      energy[veg][band].Tfoliage_fbcount = 0;
      energy[veg][band].Tcanopy_fbcount = 0;
      energy[veg][band].Tsurf_fbcount = 0;
      for ( index = 0; index < Nnodes-1; index++ ) {
	energy[veg][band].T_fbcount[index] = 0;
      }
    }
  }

  // Compute treeline adjustment factors
  for ( band = 0; band < options.SNOW_BAND; band++ ) {
    if ( soil_con->AboveTreeLine[band] ) {
      Cv = 0;
      for ( veg = 0 ; veg < veg_con[0].vegetat_type_num ; veg++ ) {
        if ( veg_lib[veg_con[veg].veg_class].overstory )
          Cv += veg_con[veg].Cv;
      }
      TreeAdjustFactor[band] = 1. / ( 1. - Cv );
    }
    else TreeAdjustFactor[band] = 1.;
  }

  // Initialize crop structures
  for ( veg = 0 ; veg < veg_con[0].vegetat_type_num ; veg++ ) {
    if (veg_con[veg].crop_frac_active) {
      for ( band = 0; band < options.SNOW_BAND; band++ ) {
      for (idx = veg_con[veg].crop_frac_idx; idx<veg_con[veg].crop_frac_idx+2; idx++) {

        // Copy veg_var state data
        if (idx % 2 == 0)
          all_vars_crop->veg_var[idx][band].Wdew = 0;
        else
          all_vars_crop->veg_var[idx][band].Wdew = veg_var[veg][band].Wdew;
        if (options.CARBON) {
          for (cidx=0; cidx<options.Ncanopy; cidx++) {
            all_vars_crop->veg_var[idx][band].NscaleFactor[cidx] = veg_var[veg][band].NscaleFactor[cidx];
            all_vars_crop->veg_var[idx][band].aPARLayer[cidx] = veg_var[veg][band].aPARLayer[cidx];
            all_vars_crop->veg_var[idx][band].CiLayer[cidx] = veg_var[veg][band].CiLayer[cidx];
            all_vars_crop->veg_var[idx][band].rsLayer[cidx] = veg_var[veg][band].rsLayer[cidx];
          }
        }
        all_vars_crop->veg_var[idx][band].Ci = veg_var[veg][band].Ci;
        all_vars_crop->veg_var[idx][band].rc = veg_var[veg][band].rc;
        all_vars_crop->veg_var[idx][band].NPPfactor = veg_var[veg][band].NPPfactor;
        all_vars_crop->veg_var[idx][band].AnnualNPP = veg_var[veg][band].AnnualNPP;
        all_vars_crop->veg_var[idx][band].AnnualNPPPrev = veg_var[veg][band].AnnualNPPPrev;

        // Copy veg_var flux data
        all_vars_crop->veg_var[idx][band].canopyevap = veg_var[veg][band].canopyevap;
        all_vars_crop->veg_var[idx][band].throughfall = veg_var[veg][band].throughfall;
        all_vars_crop->veg_var[idx][band].aPAR = veg_var[veg][band].aPAR;
        all_vars_crop->veg_var[idx][band].GPP = veg_var[veg][band].GPP;
        all_vars_crop->veg_var[idx][band].Rphoto = veg_var[veg][band].Rphoto;
        all_vars_crop->veg_var[idx][band].Rdark = veg_var[veg][band].Rdark;
        all_vars_crop->veg_var[idx][band].Rmaint = veg_var[veg][band].Rmaint;
        all_vars_crop->veg_var[idx][band].Rgrowth = veg_var[veg][band].Rgrowth;
        all_vars_crop->veg_var[idx][band].Raut = veg_var[veg][band].Raut;
        all_vars_crop->veg_var[idx][band].NPP = veg_var[veg][band].NPP;
        all_vars_crop->veg_var[idx][band].Litterfall = veg_var[veg][band].Litterfall;

        // Copy cell state data
	for ( lidx = 0; lidx < 2; lidx++ ) {
          all_vars_crop->cell[idx][band].aero_resist[lidx] = cell[veg][band].aero_resist[lidx];
        }
        all_vars_crop->cell[idx][band].asat = cell[veg][band].asat;
        all_vars_crop->cell[idx][band].CLitter = cell[veg][band].CLitter;
        all_vars_crop->cell[idx][band].CInter = cell[veg][band].CInter;
        all_vars_crop->cell[idx][band].CSlow = cell[veg][band].CSlow;
	for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
          all_vars_crop->cell[idx][band].layer[lidx].bare_evap_frac = cell[veg][band].layer[lidx].bare_evap_frac;
          all_vars_crop->cell[idx][band].layer[lidx].Cs = cell[veg][band].layer[lidx].Cs;
          all_vars_crop->cell[idx][band].layer[lidx].kappa = cell[veg][band].layer[lidx].kappa;
          all_vars_crop->cell[idx][band].layer[lidx].moist = cell[veg][band].layer[lidx].moist;
	  for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ )
            all_vars_crop->cell[idx][band].layer[lidx].ice[frost_area] = cell[veg][band].layer[lidx].ice[frost_area];
          all_vars_crop->cell[idx][band].layer[lidx].phi = cell[veg][band].layer[lidx].phi;
          all_vars_crop->cell[idx][band].layer[lidx].T = cell[veg][band].layer[lidx].T;
          all_vars_crop->cell[idx][band].layer[lidx].zwt = cell[veg][band].layer[lidx].zwt;
        }

        // Copy cell flux data
        all_vars_crop->cell[idx][band].baseflow = cell[veg][band].baseflow;
	for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
          all_vars_crop->cell[idx][band].layer[lidx].evap = cell[veg][band].layer[lidx].evap;
        }
        all_vars_crop->cell[idx][band].inflow = cell[veg][band].inflow;
	for ( lidx = 0; lidx < N_PET_TYPES; lidx++ ) {
          all_vars_crop->cell[idx][band].pot_evap[lidx] = cell[veg][band].pot_evap[lidx];
        }
        all_vars_crop->cell[idx][band].runoff = cell[veg][band].runoff;
        all_vars_crop->cell[idx][band].RhLitter = cell[veg][band].RhLitter;
        all_vars_crop->cell[idx][band].RhLitter2Atm = cell[veg][band].RhLitter2Atm;
        all_vars_crop->cell[idx][band].RhInter = cell[veg][band].RhInter;
        all_vars_crop->cell[idx][band].RhSlow = cell[veg][band].RhSlow;
        all_vars_crop->cell[idx][band].RhTot = cell[veg][band].RhTot;
        all_vars_crop->cell[idx][band].rootmoist = cell[veg][band].rootmoist;
        all_vars_crop->cell[idx][band].wetness = cell[veg][band].wetness;
        all_vars_crop->cell[idx][band].zwt = cell[veg][band].zwt;
        all_vars_crop->cell[idx][band].zwt_lumped = cell[veg][band].zwt_lumped;

        // Copy snow state data
        all_vars_crop->snow[idx][band].albedo = snow[veg][band].albedo;
        all_vars_crop->snow[idx][band].canopy_albedo = snow[veg][band].canopy_albedo;
        all_vars_crop->snow[idx][band].coldcontent = snow[veg][band].coldcontent;
        all_vars_crop->snow[idx][band].coverage = snow[veg][band].coverage;
        all_vars_crop->snow[idx][band].density = snow[veg][band].density;
        all_vars_crop->snow[idx][band].depth = snow[veg][band].depth;
        all_vars_crop->snow[idx][band].last_snow = snow[veg][band].last_snow;
        all_vars_crop->snow[idx][band].max_snow_depth = snow[veg][band].max_snow_depth;
        all_vars_crop->snow[idx][band].MELTING = snow[veg][band].MELTING;
        all_vars_crop->snow[idx][band].pack_temp = snow[veg][band].pack_temp;
        all_vars_crop->snow[idx][band].pack_water = snow[veg][band].pack_water;
        all_vars_crop->snow[idx][band].snow = snow[veg][band].snow;
        if (idx % 2 == 0)
          all_vars_crop->snow[idx][band].snow_canopy = 0;
        else
          all_vars_crop->snow[idx][band].snow_canopy = snow[veg][band].snow_canopy;
        all_vars_crop->snow[idx][band].store_coverage = snow[veg][band].store_coverage;
        all_vars_crop->snow[idx][band].store_snow = snow[veg][band].store_snow;
        all_vars_crop->snow[idx][band].store_swq = snow[veg][band].store_swq;
        all_vars_crop->snow[idx][band].surf_temp = snow[veg][band].surf_temp;
        all_vars_crop->snow[idx][band].surf_temp_fbcount = snow[veg][band].surf_temp_fbcount;
        all_vars_crop->snow[idx][band].surf_temp_fbflag = snow[veg][band].surf_temp_fbflag;
        all_vars_crop->snow[idx][band].surf_water = snow[veg][band].surf_water;
        all_vars_crop->snow[idx][band].swq = snow[veg][band].swq;
        all_vars_crop->snow[idx][band].snow_distrib_slope = snow[veg][band].snow_distrib_slope;
        all_vars_crop->snow[idx][band].tmp_int_storage = snow[veg][band].tmp_int_storage;

        // Copy snow flux data
        all_vars_crop->snow[idx][band].blowing_flux = snow[veg][band].blowing_flux;
        all_vars_crop->snow[idx][band].canopy_vapor_flux = snow[veg][band].canopy_vapor_flux;
        all_vars_crop->snow[idx][band].mass_error = snow[veg][band].mass_error;
        all_vars_crop->snow[idx][band].melt = snow[veg][band].melt;
        all_vars_crop->snow[idx][band].Qnet = snow[veg][band].Qnet;
        all_vars_crop->snow[idx][band].surface_flux = snow[veg][band].surface_flux;
        all_vars_crop->snow[idx][band].transport = snow[veg][band].transport;
        all_vars_crop->snow[idx][band].vapor_flux = snow[veg][band].albedo;

        // Copy energy state data
        all_vars_crop->energy[idx][band].AlbedoLake = energy[veg][band].AlbedoLake;
        all_vars_crop->energy[idx][band].AlbedoOver = energy[veg][band].AlbedoOver;
        all_vars_crop->energy[idx][band].AlbedoUnder = energy[veg][band].AlbedoUnder;
        all_vars_crop->energy[idx][band].frozen = energy[veg][band].frozen;
        all_vars_crop->energy[idx][band].Nfrost = energy[veg][band].Nfrost;
        all_vars_crop->energy[idx][band].Nthaw = energy[veg][band].Nthaw;
        all_vars_crop->energy[idx][band].T1_index = energy[veg][band].T1_index;
        all_vars_crop->energy[idx][band].Tcanopy = energy[veg][band].Tcanopy;
        all_vars_crop->energy[idx][band].Tcanopy_fbcount = energy[veg][band].Tcanopy_fbcount;
        all_vars_crop->energy[idx][band].Tcanopy_fbflag = energy[veg][band].Tcanopy_fbflag;
        all_vars_crop->energy[idx][band].Tfoliage = energy[veg][band].Tfoliage;
        all_vars_crop->energy[idx][band].Tfoliage_fbcount = energy[veg][band].Tfoliage_fbcount;
        all_vars_crop->energy[idx][band].Tfoliage_fbflag = energy[veg][band].Tfoliage_fbflag;
        all_vars_crop->energy[idx][band].Tsurf = energy[veg][band].Tsurf;
        all_vars_crop->energy[idx][band].Tsurf_fbcount = energy[veg][band].Tsurf_fbcount;
        all_vars_crop->energy[idx][band].Tsurf_fbflag = energy[veg][band].Tsurf_fbflag;
        all_vars_crop->energy[idx][band].unfrozen = energy[veg][band].unfrozen;
        for (lidx=0; lidx<2; lidx++) {
          all_vars_crop->energy[idx][band].Cs[lidx] = energy[veg][band].Cs[lidx];
          all_vars_crop->energy[idx][band].kappa[lidx] = energy[veg][band].kappa[lidx];
        }
        for (index=0; index<Nnodes; index++) {
          all_vars_crop->energy[idx][band].Cs_node[index] = energy[veg][band].Cs_node[index];
          all_vars_crop->energy[idx][band].fdepth[index] = energy[veg][band].fdepth[index];
          all_vars_crop->energy[idx][band].ice[index] = energy[veg][band].ice[index];
          all_vars_crop->energy[idx][band].kappa_node[index] = energy[veg][band].kappa_node[index];
          all_vars_crop->energy[idx][band].moist[index] = energy[veg][band].moist[index];
          all_vars_crop->energy[idx][band].T[index] = energy[veg][band].T[index];
          all_vars_crop->energy[idx][band].T_fbcount[index] = energy[veg][band].T_fbcount[index];
          all_vars_crop->energy[idx][band].T_fbflag[index] = energy[veg][band].T_fbflag[index];
          all_vars_crop->energy[idx][band].tdepth[index] = energy[veg][band].tdepth[index];
        }

        // Copy energy flux data
        all_vars_crop->energy[idx][band].advected_sensible = energy[veg][band].advected_sensible;
        all_vars_crop->energy[idx][band].advection = energy[veg][band].advection;
        all_vars_crop->energy[idx][band].AtmosError = energy[veg][band].AtmosError;
        all_vars_crop->energy[idx][band].AtmosLatent = energy[veg][band].AtmosLatent;
        all_vars_crop->energy[idx][band].AtmosLatentSub = energy[veg][band].AtmosLatentSub;
        all_vars_crop->energy[idx][band].AtmosSensible = energy[veg][band].AtmosSensible;
        all_vars_crop->energy[idx][band].canopy_advection = energy[veg][band].canopy_advection;
        all_vars_crop->energy[idx][band].canopy_latent = energy[veg][band].canopy_latent;
        all_vars_crop->energy[idx][band].canopy_latent_sub = energy[veg][band].canopy_latent_sub;
        all_vars_crop->energy[idx][band].canopy_refreeze = energy[veg][band].canopy_refreeze;
        all_vars_crop->energy[idx][band].canopy_sensible = energy[veg][band].canopy_sensible;
        all_vars_crop->energy[idx][band].deltaCC = energy[veg][band].deltaCC;
        all_vars_crop->energy[idx][band].deltaH = energy[veg][band].deltaH;
        all_vars_crop->energy[idx][band].error = energy[veg][band].error;
        all_vars_crop->energy[idx][band].fusion = energy[veg][band].fusion;
        all_vars_crop->energy[idx][band].grnd_flux = energy[veg][band].grnd_flux;
        all_vars_crop->energy[idx][band].latent = energy[veg][band].latent;
        all_vars_crop->energy[idx][band].latent_sub = energy[veg][band].latent_sub;
        all_vars_crop->energy[idx][band].longwave = energy[veg][band].longwave;
        all_vars_crop->energy[idx][band].LongOverIn = energy[veg][band].LongOverIn;
        all_vars_crop->energy[idx][band].LongUnderIn = energy[veg][band].LongUnderIn;
        all_vars_crop->energy[idx][band].LongUnderOut = energy[veg][band].LongUnderOut;
        all_vars_crop->energy[idx][band].melt_energy = energy[veg][band].melt_energy;
        all_vars_crop->energy[idx][band].NetLongAtmos = energy[veg][band].NetLongAtmos;
        all_vars_crop->energy[idx][band].NetLongOver = energy[veg][band].NetLongOver;
        all_vars_crop->energy[idx][band].NetLongUnder = energy[veg][band].NetLongUnder;
        all_vars_crop->energy[idx][band].NetShortAtmos = energy[veg][band].NetShortAtmos;
        all_vars_crop->energy[idx][band].NetShortGrnd = energy[veg][band].NetShortGrnd;
        all_vars_crop->energy[idx][band].NetShortOver = energy[veg][band].NetShortOver;
        all_vars_crop->energy[idx][band].NetShortUnder = energy[veg][band].NetShortUnder;
        all_vars_crop->energy[idx][band].out_long_canopy = energy[veg][band].out_long_canopy;
        all_vars_crop->energy[idx][band].out_long_surface = energy[veg][band].out_long_surface;
        all_vars_crop->energy[idx][band].refreeze_energy = energy[veg][band].refreeze_energy;
        all_vars_crop->energy[idx][band].sensible = energy[veg][band].sensible;
        all_vars_crop->energy[idx][band].shortwave = energy[veg][band].shortwave;
        all_vars_crop->energy[idx][band].ShortOverIn = energy[veg][band].ShortOverIn;
        all_vars_crop->energy[idx][band].ShortUnderIn = energy[veg][band].ShortUnderIn;
        all_vars_crop->energy[idx][band].snow_flux = energy[veg][band].snow_flux;

      }
      }
    }
  }

  return(0);
}
/******************************************************************************
 * @brief    Compute the state variables (energy balance, water balance,
 *           and snow components) that are derived from the variables that
 *           are stored in state files.
 *****************************************************************************/
void
compute_derived_state_vars(all_vars_struct *all_vars,
                           soil_con_struct *soil_con,
                           veg_con_struct  *veg_con)
{
    extern global_param_struct global_param;
    extern option_struct       options;

    char                       FIRST_VEG;
    size_t                     Nveg;
    size_t                     veg;
    size_t                     lidx;
    size_t                     band;
    size_t                     tmpTshape[] = {
        options.Nlayer, options.Nnode,
        options.Nfrost + 1
    };
    size_t                     tmpZshape[] = {
        options.Nlayer, options.Nnode
    };
    int                        ErrorFlag;
    double                     Cv;
    double                     moist[MAX_VEG][MAX_BANDS][MAX_LAYERS];
    double                     dt_thresh;
    double                     tmp_runoff;
    double                  ***tmpT;
    double                   **tmpZ;

    cell_data_struct         **cell;
    energy_bal_struct        **energy;
    snow_data_struct         **snow;

    cell = all_vars->cell;
    energy = all_vars->energy;
    snow = all_vars->snow;
    Nveg = veg_con[0].vegetat_type_num;

    // allocate memory for tmpT and tmpZ
    malloc_3d_double(tmpTshape, &tmpT);
    malloc_2d_double(tmpZshape, &tmpZ);

    /******************************************
       Compute derived soil layer vars
    ******************************************/
    for (veg = 0; veg <= Nveg; veg++) {
        // Initialize soil for existing vegetation types
        Cv = veg_con[veg].Cv;

        if (Cv > 0) {
            for (band = 0; band < options.SNOW_BAND; band++) {
                // Initialize soil for existing snow elevation bands
                if (soil_con->AreaFract[band] > 0.) {
                    // set up temporary moist arrays
                    for (lidx = 0; lidx < options.Nlayer; lidx++) {
                        moist[veg][band][lidx] =
                            cell[veg][band].layer[lidx].moist;
                    }

                    // compute saturated area and water table
                    compute_runoff_and_asat(soil_con, moist[veg][band], 0,
                                            &(cell[veg][band].asat),
                                            &tmp_runoff);
                    wrap_compute_zwt(soil_con, &(cell[veg][band]));
                }
            }
        }
    }

    /******************************************
       Compute derived soil snow state vars
    ******************************************/
    for (veg = 0; veg <= Nveg; veg++) {
        for (band = 0; band < options.SNOW_BAND; band++) {
            if (snow[veg][band].density > 0.) {
                snow[veg][band].depth = CONST_RHOFW * snow[veg][band].swq /
                                        snow[veg][band].density;
            }
        }
    }

    /******************************************
       Compute soil thermal node properties
    ******************************************/
    FIRST_VEG = true;
    for (veg = 0; veg <= Nveg; veg++) {
        // Initialize soil for existing vegetation types
        Cv = veg_con[veg].Cv;

        if (Cv > 0) {
            for (band = 0; band < options.SNOW_BAND; band++) {
                // Initialize soil for existing snow elevation bands
                if (soil_con->AreaFract[band] > 0.) {
                    /** Set soil properties for all soil nodes **/
                    if (FIRST_VEG) {
                        FIRST_VEG = false;
                        set_node_parameters(soil_con->Zsum_node,
                                            soil_con->max_moist_node,
                                            soil_con->expt_node,
                                            soil_con->bubble_node,
                                            soil_con->alpha, soil_con->beta,
                                            soil_con->gamma, soil_con->depth,
                                            soil_con->max_moist, soil_con->expt,
                                            soil_con->bubble,
                                            options.Nnode, options.Nlayer);
                    }

                    // set soil moisture properties for all soil thermal nodes
                    if (options.FULL_ENERGY || options.FROZEN_SOIL) {
                        ErrorFlag =
                            distribute_node_moisture_properties(
                                energy[veg][band].moist,
                                energy[veg][band].ice,
                                energy[veg][band].kappa_node,
                                energy[veg][band].Cs_node,
                                soil_con->Zsum_node,
                                energy[veg][band].T,
                                soil_con->max_moist_node,
                                soil_con->expt_node,
                                soil_con->bubble_node,
                                moist[veg][band],
                                soil_con->depth,
                                soil_con->soil_dens_min,
                                soil_con->bulk_dens_min,
                                soil_con->quartz,
                                soil_con->soil_density,
                                soil_con->bulk_density,
                                soil_con->organic,
                                options.Nnode, options.Nlayer,
                                soil_con->FS_ACTIVE);
                        if (ErrorFlag == ERROR) {
                            log_err("Error setting physical properties for "
                                    "soil thermal nodes");
                        }
                    }

                    // Check node spacing v time step
                    // (note this is only approximate since heat capacity and
                    // conductivity can change considerably during the
                    // simulation depending on soil moisture and ice content)
                    if ((options.FROZEN_SOIL &&
                         !options.QUICK_FLUX) && !options.IMPLICIT) {
                        // in seconds
                        dt_thresh = 0.5 * energy[veg][band].Cs_node[1] /
                                    energy[veg][band].kappa_node[1] *
                                    pow((soil_con->dz_node[1]),
                                        2);
                        if (global_param.dt > dt_thresh) {
                            log_err("You are currently running FROZEN SOIL "
                                    "with an explicit method (IMPLICIT is "
                                    "set to FALSE).  For the explicit method "
                                    "to be stable, time step %f seconds is too "
                                    "large for the given thermal node spacing "
                                    "%f m, soil heat capacity %f J/m3/K, and "
                                    "soil thermal conductivity %f J/m/s/K.  "
                                    "Either set IMPLICIT to TRUE in your "
                                    "global parameter file (this is the "
                                    "recommended action), or decrease time "
                                    "step length to <= %f seconds, or decrease "
                                    "the number of soil thermal nodes.",
                                    global_param.dt,
                                    soil_con->dz_node[1],
                                    energy[veg][band].Cs_node[1],
                                    energy[veg][band].kappa_node[1], dt_thresh);
                        }
                    }

                    /* calculate soil layer temperatures  */
                    if (options.QUICK_FLUX) {
                        ErrorFlag =
                            estimate_layer_temperature_quick_flux(
                                cell[veg][band].layer,
                                soil_con->depth, soil_con->dp,
                                energy[veg][band].T[0],
                                energy[veg][band].T[1],
                                soil_con->avg_temp);
                        if (ErrorFlag == ERROR) {
                            log_err("Error calculating layer temperature "
                                    "using QUICK_FLUX option");
                        }
                    }
                    else {
                        estimate_frost_temperature_and_depth(
                            tmpT,
                            tmpZ,
                            soil_con->Zsum_node,
                            energy[veg][band].T,
                            soil_con->depth,
                            soil_con->frost_fract,
                            soil_con->frost_slope,
                            options.Nnode,
                            options.Nlayer);
                        ErrorFlag = estimate_layer_temperature(
                            cell[veg][band].layer,
                            tmpT,
                            tmpZ,
                            soil_con->Zsum_node,
                            soil_con->depth,
                            options.Nnode,
                            options.Nlayer);
                        if (ErrorFlag == ERROR) {
                            log_err("Error calculating layer temperature");
                        }
                    }

                    /* Find freezing and thawing front depths */
                    if (!options.QUICK_FLUX && soil_con->FS_ACTIVE) {
                        find_0_degree_fronts(&energy[veg][band],
                                             soil_con->Zsum_node,
                                             energy[veg][band].T,
                                             options.Nnode);
                    }
                }
            }
        }
    }
    // free memory for tmpT and tmpZ
    free_3d_double(tmpTshape, tmpT);
    free_2d_double(tmpZshape, tmpZ);
}
void initialize_model_state(dist_prcp_struct    *prcp,
			    dmy_struct           dmy,
			    global_param_struct *global_param,
                            filep_struct         filep, 
			    int                  cellnum,
		            int                  Nveg,
                            int                  Nnodes,
			    int                  Ndist,
                            double               surf_temp,
                            soil_con_struct     *soil_con,
			    veg_con_struct      *veg_con,
			    char                *init_STILL_STORM,
			    int                 *init_DRY_TIME,
			    save_data_struct    *save_data)
/**********************************************************************
  initialize_model_state       Keith Cherkauer	    April 17, 2000

  This routine initializes the model state (energy balance, water balance,
  and snow components).  If a state file is provided to the model than its
  contents are checked to see if it agrees with the current simulation
  set-up, if so it is used to initialize the model state.  If no state
  file is provided the model initializes all variables with defaults and
  the user should expect to throw out the beginning of the simulation 
  period as model start-up.

  UNITS: (m, s, kg, C, moisture in mm) unless otherwise specified

  Modifications:
  4-17-00 Modified from initialize_energy_bal.c and initialize_snow.c
          to provide a single controlling routine for initializing the
          model state.
  2-10-03 Fixed looping problem with initialization of soil moisture. KAC
  3-12-03 Modified so that soil layer ice content is only calculated 
          when frozen soil is implemented and active in the current 
          grid cell.                                                KAC
  04-10-03 Modified to read storm parameters from model state file.  KAC
  07-May-04 Initialize soil_con->dz_node[Nnodes] to 0.0, since it is
	    accessed in set_node_parameters().			TJB
  2006-Sep-14 Implemented ALMA-compliant input and output; uses the new
	      save_data structure to track changes in moisture storage
	      over each time step; this needs initialization here.  TJB
  2006-Oct-25 Inserted "if (veg < Nveg)" before the line updating
	      save_data->wdew, since Wdew is undefined for veg == Nveg. TJB
  2006-Oct-26 Merged infiles and outfiles structs into filep_struct;
	      This included removing the unused init_snow file. TJB
  2006-Nov-15 Changed initial state reading from statefile to init_state GCT
**********************************************************************/
{
  extern option_struct options;
  extern veg_lib_struct  *veg_lib;
#if LINK_DEBUG
  extern debug_struct debug;
#endif
#if QUICK_FS
  extern double temps[];
#endif

  char     tmpstr[MAXSTRING];
  char     ErrStr[MAXSTRING];
  char     FIRST_VEG;
  int      i, j, ii, veg, index, dist;
  int      nidx, lidx;
  int      tmpint;
  int      dry;
  int      band;
  int      zindex;
  double   sum, Lsum, Zsum, dp, Ltotal;
  double   tmpdp, tmpadj;
  double  *kappa, *Cs, *M;
  double   moist[MAX_VEG][MAX_BANDS][MAX_LAYERS];
  double   ice[MAX_VEG][MAX_BANDS][MAX_LAYERS];
  double   unfrozen, frozen;
  double **layer_ice;
  double **layer_tmp;
  double  *EMPTY;
#if QUICK_FS
  double   Aufwc, Bufwc;
#endif
  char    *EMPTY_C;
  double  Cv;
  double  mu;
  double                  TreeAdjustFactor[MAX_BANDS];

  cell_data_struct     ***cell;
  snow_data_struct      **snow;
  energy_bal_struct     **energy;
  veg_var_struct       ***veg_var;

  cell    = prcp->cell;
  veg_var = prcp->veg_var;
  snow    = prcp->snow;
  energy  = prcp->energy;
  
  dp = soil_con->dp;
  Ltotal = 0;
  for(index=0;index<options.Nlayer;index++) Ltotal += soil_con->depth[index];
  FIRST_VEG = TRUE;

  // initialize storm parameters to start a new simulation
  (*init_DRY_TIME) = -999;
  
  /********************************************
    Initialize all snow pack variables 
    - some may be reset if state file present
  ********************************************/

  initialize_snow(snow, Nveg, cellnum);

  /********************************************
    Initialize all soil layer variables 
    - some may be reset if state file present
  ********************************************/

  initialize_soil(cell[WET], soil_con, Nveg);

  /********************************************
    Initialize all vegetation variables 
    - some may be reset if state file present
  ********************************************/

  initialize_veg(veg_var[WET], veg_con, global_param);

#if QUICK_FS
  if(options.FROZEN_SOIL) {

    /***********************************************************
      Prepare table of maximum unfrozen water content values
      - This linearizes the equation for maximum unfrozen water
        content, reducing computation time for the frozen soil
        model.
    ***********************************************************/

    for(lidx=0;lidx<options.Nlayer;lidx++) { 
      for(ii=0;ii<QUICK_FS_TEMPS;ii++) {
	Aufwc = maximum_unfrozen_water(temps[ii], 1.0, 
				       soil_con->bubble[lidx], 
				       soil_con->expt[lidx]);
	Bufwc = maximum_unfrozen_water(temps[ii+1], 1.0, 
				       soil_con->bubble[lidx], 
				       soil_con->expt[lidx]);
	soil_con->ufwc_table_layer[lidx][ii][0] 
	  = linear_interp(0., temps[ii], temps[ii+1], Aufwc, Bufwc);
	soil_con->ufwc_table_layer[lidx][ii][1] 
	  = (Bufwc - Aufwc) / (temps[ii+1] - temps[ii]);
      }
    }
  }  
#endif

  /************************************************************************
    CASE 1: Not using quick ground heat flux, and initial conditions files 
    provided
  ************************************************************************/

  if(options.INIT_STATE) {

    read_initial_model_state(filep.init_state, prcp, global_param,  
			     Nveg, options.SNOW_BAND, cellnum, soil_con,
			     Ndist, init_STILL_STORM, init_DRY_TIME);

    for( veg = 0; veg <= Nveg; veg++ ) 
      for( band = 0; band < options.SNOW_BAND; band++ )
	for( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	  moist[veg][band][lidx] = cell[0][veg][band].layer[lidx].moist;
	  ice[veg][band][lidx] = cell[0][veg][band].layer[lidx].ice;
	}

  }
  
  /************************************************************************
    CASE 2: Initialize soil if using quick heat flux, and no initial
    soil properties file given
  ************************************************************************/
    
  else if(options.QUICK_FLUX) {

    for ( veg = 0 ; veg <= Nveg ; veg++) {
      for ( band = 0; band < options.SNOW_BAND; band++ ) {

	/* Initialize soil node temperatures and thicknesses */

	soil_con->dz_node[0] = soil_con->depth[0];
	soil_con->dz_node[1] = soil_con->depth[0];
	soil_con->dz_node[2] = 2. * (dp - 1.5 * soil_con->depth[0]);
	energy[veg][band].T[0] = surf_temp;
	energy[veg][band].T[1] = surf_temp;
	energy[veg][band].T[2] = soil_con->avg_temp;

	for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	  moist[veg][band][lidx] = soil_con->init_moist[lidx];
	  ice[veg][band][lidx] = 0.;
	}

      }
    }
  }

  /*****************************************************************
    CASE 3: Initialize Energy Balance Variables if not using quick
    ground heat flux, and no Initial Condition File Given 
  *****************************************************************/
  else if(!options.QUICK_FLUX) {
    for ( veg = 0 ; veg <= Nveg ; veg++) {
      for ( band = 0; band < options.SNOW_BAND; band++ ) {

	/* Initialize soil node temperatures and thicknesses 
	 Nodes set at surface, the depth of the first layer,
	 twice the depth of the first layer, and at the
	 damping depth.  Extra nodes are placed equal distance
	 between the damping depth and twice the depth of the
	 first layer. */

	energy[veg][band].T[0] = surf_temp;
	soil_con->dz_node[0] = soil_con->depth[0];
	soil_con->dz_node[1] = soil_con->depth[0];
	soil_con->dz_node[2] = soil_con->depth[0];
	energy[veg][band].T[Nnodes-1] = soil_con->avg_temp;
	energy[veg][band].T[1] = exp_interp(soil_con->depth[0], 0., dp, 
					    surf_temp, soil_con->avg_temp);
	energy[veg][band].T[2] = exp_interp(2. * soil_con->depth[0], 0., dp, 
					    surf_temp, soil_con->avg_temp);
	
        Zsum   = 2. * soil_con[0].depth[0];
        tmpdp  = dp - soil_con[0].depth[0] * 2.5;
        tmpadj = 3.5;
        for(index=3;index<Nnodes-1;index++) {
          if(veg==0 && band==0)
	    soil_con->dz_node[index] = tmpdp/(((double)Nnodes-tmpadj));
          Zsum += (soil_con->dz_node[index]
                   +soil_con->dz_node[index-1])/2.;
          energy[veg][band].T[index] = exp_interp(Zsum,0.,soil_con[0].dp,
                                                  surf_temp,
                                                  soil_con[0].avg_temp);
        }
	if(veg==0 && band==0) {
	  soil_con->dz_node[Nnodes-1] = (dp - Zsum 
					 - soil_con->dz_node[Nnodes-2] 
					 / 2. ) * 2.;
	  Zsum += (soil_con->dz_node[Nnodes-2]
		   +soil_con->dz_node[Nnodes-1])/2.;
	  if((int)(Zsum*1000+0.5) != (int)(dp*1000+0.5)) {
	    sprintf(ErrStr,"Sum of thermal node thicknesses (%f) in initialize_model_state do not equal dp (%f), check initialization procedure",Zsum,dp);
	    nrerror(ErrStr);
	  }
        }

	for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	  moist[veg][band][lidx] = soil_con->init_moist[lidx];
	  ice[veg][band][lidx] = 0.;
	}

      }
    }
  }

  /*********************************
    CASE 4: Unknown option
  *********************************/
  else {
    for ( veg = 0 ; veg <= Nveg ; veg++) {
      for ( band = 0; band < options.SNOW_BAND; band++ ) {
	for ( index = 0; index < options.Nlayer; index++ ) {
	  soil_con->dz_node[index] = 1.;
	}
      }
    }
  }

  /******************************************
    Initialize soil thermal node properties 
  ******************************************/

/* dz_node[Nnodes] is accessed later despite not being set. This can
  cause run-time errors on some platforms. Therefore, set it to zero */
  soil_con->dz_node[Nnodes]=0.0;

  if ( options.GRND_FLUX ) {

    for ( veg = 0 ; veg <= Nveg ; veg++) {
      for( band = 0; band < options.SNOW_BAND; band++ ) {
	
	/** Set soil properties for all soil nodes **/
	if(FIRST_VEG) {
	  FIRST_VEG = FALSE;
	  set_node_parameters(soil_con->dz_node, soil_con->max_moist_node,
			      soil_con->expt_node, soil_con->bubble_node,
			      soil_con->alpha, soil_con->beta,
			      soil_con->gamma, soil_con->depth,
			      soil_con->max_moist, soil_con->expt, 
			      soil_con->bubble, soil_con->quartz, 
			      soil_con->layer_node_fract,
#if QUICK_FS
			      soil_con->ufwc_table_node,
#endif
			      Nnodes, options.Nlayer, soil_con->FS_ACTIVE);
	  
	  sum = soil_con->dz_node[0]/2. + soil_con->dz_node[Nnodes-1]/2.;
	  for(nidx=1;nidx<Nnodes-1;nidx++) sum += soil_con->dz_node[nidx];
	}
	
	/* set soil moisture properties for all soil thermal nodes */
	distribute_node_moisture_properties(energy[veg][band].moist,
					    energy[veg][band].ice,
					    energy[veg][band].kappa_node,
					    energy[veg][band].Cs_node,
					    soil_con->dz_node,
					    energy[veg][band].T,
					    soil_con->max_moist_node,
#if QUICK_FS
					    soil_con->ufwc_table_node,
#else
					    soil_con->expt_node,
					    soil_con->bubble_node,
#endif
					    moist[veg][band], soil_con->depth,
					    soil_con->soil_density,
					    soil_con->bulk_density,
					    soil_con->quartz,
					    Nnodes, options.Nlayer,
					    soil_con->FS_ACTIVE);
	
	/* initialize layer moistures and ice contents */
	for(dry = 0; dry < Ndist; dry++) {
	  for(lidx=0;lidx<options.Nlayer;lidx++) {
	    cell[dry][veg][band].layer[lidx].moist = moist[veg][band][lidx];
	    cell[dry][veg][band].layer[lidx].ice = ice[veg][band][lidx];
	  }
	  if(soil_con->FS_ACTIVE && options.FROZEN_SOIL)
	    estimate_layer_ice_content(cell[dry][veg][band].layer,
				       soil_con->dz_node,
				       energy[veg][band].T,
				       soil_con->max_moist_node,
#if QUICK_FS
				       soil_con->ufwc_table_node,
#else
				       soil_con->expt_node,
				       soil_con->bubble_node,
#endif
				       soil_con->depth,
				       soil_con->max_moist,
#if QUICK_FS
				       soil_con->ufwc_table_layer,
#else
				       soil_con->expt,
				       soil_con->bubble,
#endif
				       soil_con->bulk_density,
				       soil_con->soil_density,
				       soil_con->quartz, 
				       soil_con->layer_node_fract,
				       Nnodes, options.Nlayer, 
				       soil_con->FS_ACTIVE);
	
	}
	
	/* Find freezing and thawing front depths */
	if(!options.QUICK_FLUX && soil_con->FS_ACTIVE) 
	  find_0_degree_fronts(&energy[veg][band], soil_con->dz_node,
			       energy[veg][band].T, Nnodes);
	
      }
    }	
  }  

  // Compute treeline adjustment factors
  for ( band = 0; band < options.SNOW_BAND; band++ ) {
    if ( soil_con->AboveTreeLine[band] ) {
      Cv = 0;
      for ( veg = 0 ; veg < veg_con[0].vegetat_type_num ; veg++ ) {
        if ( veg_lib[veg_con[veg].veg_class].overstory )
          Cv += veg_con[veg].Cv;
      }
      TreeAdjustFactor[band] = 1. / ( 1. - Cv );
    }
    else TreeAdjustFactor[band] = 1.;
  }

  // Save initial moisture storages for differencing at end of time step
  save_data->total_soil_moist = 0;
  save_data->swe = 0;
  save_data->wdew = 0;
  for( veg = 0; veg <= Nveg; veg++ ) {

    if ( veg < veg_con[0].vegetat_type_num )
      Cv = veg_con[veg].Cv;
    else
      Cv = (1.0 - veg_con[0].Cv_sum);

    if ( Cv > 0 ) {

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

        if(dist==0)
          mu = prcp[0].mu[veg];
        else
          mu = 1. - prcp[0].mu[veg];

        for( band = 0; band < options.SNOW_BAND; band++ ) {

          if (soil_con->AreaFract[band] > 0.
              && ( veg == veg_con[0].vegetat_type_num
                  || ( !soil_con->AboveTreeLine[band]
                      || (soil_con->AboveTreeLine[band] && !veg_lib[veg_con[veg].veg_class].overstory)))) {

	    for(lidx=0;lidx<options.Nlayer;lidx++) {
              save_data->total_soil_moist += 
                (cell[dist][veg][band].layer[lidx].moist) // layer[].moist appears to contain both liquid and ice
                * Cv * mu * soil_con->AreaFract[band] * TreeAdjustFactor[band];
            }
            if (veg < Nveg)
              save_data->wdew += veg_var[dist][veg][band].Wdew * Cv * mu * soil_con->AreaFract[band] * TreeAdjustFactor[band];

          }

        }

      }

      for( band = 0; band < options.SNOW_BAND; band++ ) {
        save_data->swe += snow[veg][band].swq * Cv * soil_con->AreaFract[band] * TreeAdjustFactor[band];
      }

    }

  }

}
int initialize_model_state(dist_prcp_struct    *prcp,
			   dmy_struct           dmy,
			   global_param_struct *global_param,
			   filep_struct         filep,
			   int                  cellnum,
			   int                  Nveg,
			   int                  Nnodes,
			   int                  Ndist,
			   double               surf_temp, 
			   soil_con_struct     *soil_con,
			   veg_con_struct      *veg_con,
			   lake_con_struct      lake_con,
			   char               **init_STILL_STORM,
			   int                **init_DRY_TIME)
/**********************************************************************
  initialize_model_state      Keith Cherkauer	    April 17, 2000

  This routine initializes the model state (energy balance, water balance,
  and snow components).  If a state file is provided to the model than its
  contents are checked to see if it agrees with the current simulation
  set-up, if so it is used to initialize the model state.  If no state
  file is provided the model initializes all variables with defaults and
  the user should expect to throw out the beginning of the simulation 
  period as model start-up.

  UNITS: (m, s, kg, C, moisture in mm) unless otherwise specified

  Modifications:
  4-17-00 Modified from initialize_energy_bal.c and initialize_snow.c
          to provide a single controlling routine for initializing the
          model state.
  9-00    Fixed bug where initialization of soil node temperatures 
          and moitures was within two vegetation loops, thus only
          the first vegetation type was properly initialized.     KAC
  2-19-03 Modified to initialize soil and vegetation parameters for
          the dry grid cell fraction, if distributed precipitation
          is activated.                                           KAC
  11-18-02 Modified to initialize lake and wetland algorithms 
          variables.                                              LCB
  2-10-03 Fixed looping problem with initialization of soil moisture. KAC
  3-12-03 Modified so that soil layer ice content is only calculated 
          when frozen soil is implemented and active in the current 
          grid cell.                                                KAC
  04-10-03 Modified to read storm parameters from model state file.  KAC
  04-25-03 Modified to work with vegetation type specific storm 
           parameters.                                              KAC
  07-May-04 Initialize soil_con->dz_node[Nnodes] to 0.0, since it is
	    accessed in set_node_parameters().				TJB
  01-Nov-04 Added support for state files containing SPATIAL_FROST
	    and LAKE_MODEL state variables.				TJB
  2006-Apr-21 Replaced Cv (uninitialized) with lake_con.Cl[0] in
	      surfstor calculation.					TJB
  2006-Sep-23 Implemented flexible output configuration; uses the new
              save_data structure to track changes in moisture storage
              over each time step; this needs initialization here.	TJB
  2006-Oct-10 Added snow[veg][band].snow_canopy to save_data.swe.	TJB
  2006-Oct-16 Merged infiles and outfiles structs into filep_struct;
	      This included removing the unused init_snow file.		TJB
  2006-Nov-07 Removed LAKE_MODEL option.				TJB
  2007-Apr-24 Added EXP_TRANS option.					JCA
  2007-Apr-24 Zsum_node loaded into soil_con structure for later use
	      without having to recalculate.				JCA
  2007-Aug-09 Added features for EXCESS_ICE option.			JCA
  2007-Aug-21 Return value of ErrorFlag if error in
	      distribute_node_moisture_properties.			JCA
  2007-Sep-18 Check for soil moist exceeding max moist moved from
	      read_initial_model_state to here.				JCA
  2007-Oct-24 Modified initialize_lake() to return ErrorFlag.		TJB
  2008-Mar-01 Reinserted missing logic for QUICK_FS in calls to
	      distribute_node_moisture_properties() and
	      estimate_layer_ice_content().				TJB
  2009-Feb-09 Removed dz_node from call to
	      distribute_node_moisture_properties.			KAC via TJB
  2009-Feb-09 Removed dz_node from call to find_0_degree_front.		KAC via TJB
  2009-Mar-15 Modified to not call estimate_layer_ice_content() if
	      not modeling frozen soil.					KAC via TJB
  2009-Mar-16 Added resid_moist to argument list of
	      estimate_layer_ice_content().  This allows computation
	      of min_liq, the minimum allowable liquid water content
	      in each layer as a function of temperature.		TJB
  2009-Jun-09 Modified to use extension of veg_lib structure to contain
	      bare soil information.					TJB
  2009-Jul-26 Added initial estimate of incoming longwave at surface
	      (LongUnderOut) for use in canopy snow T iteration.	TJB
  2009-Jul-31 Removed extra lake/wetland veg tile.			TJB
  2009-Sep-19 Added T fbcount to count TFALLBACK occurrences.		TJB
  2009-Sep-19 Made initialization of Tfoliage more accurate for snow bands.	TJB
  2009-Sep-28 Added initialization of energy structure.			TJB
  2009-Nov-15 Added check to ensure that depth of first thermal node
	      is <= depth of first soil layer.				TJB
  2009-Dec-11 Removed initialization of save_data structure, since this
	      is now performed by the initial call to put_data().	TJB
  2009-Dec-11 Removed min_liq and options.MIN_LIQ.			TJB
  2010-Nov-11 Updated call to initialize_lake() to accommodate new
	      skip_hydro flag.						TJB
  2011-Mar-01 Updated calls to initialize_soil() and initialize_lake()
	      to accommodate new arguments.  Added more detailed validation
	      of soil moisture.						TJB
  2011-Mar-05 Added validation of initial soil moisture, ice, and snow
	      variables to make sure they are self-consistent.		TJB
  2011-May-31 Removed options.GRND_FLUX.  Now soil temperatures and 
	      ground flux are always computed.				TJB
  2011-Jun-03 Added options.ORGANIC_FRACT.  Soil properties now take
	      organic fraction into account.				TJB
  2011-Jul-05 Changed logic initializing soil temperatures so that
	      type of initialization depends solely on options.QUICK_FLUX;
	      options.Nnodes is no longer automatically reset here.	TJB
  2012-Jan-16 Removed LINK_DEBUG code					BN
  2012-Jan-28 Added stability check for case of (FROZEN_SOIL=TRUE &&
	      IMPLICIT=FALSE).						TJB
  2013-Jul-25 Fixed incorrect condition on lake initialization.		TJB
  2013-Jul-25 Moved computation of tmp_moist argument of
	      compute_runoff_and_asat() so that it would always be
	      initialized.						TJB
  2014-Jan-13 Added validation of Nnodes and dp for EXP_TRANS=TRUE.	TJB
  2014-Feb-09 Made non-spinup initial temperatures more consistent with
	      annual average air temperature and bottom boundary
	      temperature.						TJB
**********************************************************************/
{
  extern option_struct options;
  extern veg_lib_struct *veg_lib;
#if QUICK_FS
  extern double temps[];
#endif

  char     ErrStr[MAXSTRING];
  char     FIRST_VEG;
  int      i, j, ii, veg, index, dist;
  int      lidx;
  double   tmp_moist[MAX_LAYERS];
  double   tmp_runoff;
  int      dry;
  int      band;
#if SPATIAL_FROST
  int      frost_area;
#endif
  int      ErrorFlag;
  double   Cv;
  double   Zsum, dp;
  double   tmpdp, tmpadj, Bexp;
  double   Tair;
  double   tmp;
  double  *M;
  double   moist[MAX_VEG][MAX_BANDS][MAX_LAYERS];
#if SPATIAL_FROST
  double   ice[MAX_VEG][MAX_BANDS][MAX_LAYERS][FROST_SUBAREAS];
#else
  double   ice[MAX_VEG][MAX_BANDS][MAX_LAYERS];
#endif // SPATIAL_FROST
#if QUICK_FS
  double   Aufwc, Bufwc;
#endif
  double   Clake;
  double   mu;
  double   surf_swq;
  double   pack_swq;
  double   TreeAdjustFactor[MAX_BANDS];
#if EXCESS_ICE
  double   sum_mindepth, sum_depth_pre, sum_depth_post, tmp_mindepth;
#endif
  double dt_thresh;
  int tmp_lake_idx;

  cell_data_struct     ***cell;
  energy_bal_struct     **energy;
  lake_var_struct        *lake_var;
  snow_data_struct      **snow;
  veg_var_struct       ***veg_var;

  cell    = prcp->cell;
  energy  = prcp->energy;
  lake_var = &prcp->lake_var;
  snow    = prcp->snow;
  veg_var = prcp->veg_var;

  // Initialize soil depths
  dp = soil_con->dp;

  FIRST_VEG = TRUE;

  // increase initial soil surface temperature if air is very cold
  Tair = surf_temp;
  if ( surf_temp < -1. ) surf_temp = -1.;
  
  // initialize storm parameters to start a new simulation
  (*init_STILL_STORM) = (char *)malloc((Nveg+1)*sizeof(char));
  (*init_DRY_TIME)    = (int *)malloc((Nveg+1)*sizeof(int));
  for ( veg = 0 ; veg <= Nveg ; veg++ )
    (*init_DRY_TIME)[veg] = -999;
  
  /********************************************
    Initialize all snow pack variables 
    - some may be reset if state file present
  ********************************************/

  initialize_snow(snow, Nveg, cellnum);

  /********************************************
    Initialize all soil layer variables 
    - some may be reset if state file present
  ********************************************/

  initialize_soil(cell[WET], soil_con, veg_con, Nveg);
  if ( options.DIST_PRCP )
    initialize_soil(cell[DRY], soil_con, veg_con, Nveg);

  /********************************************
    Initialize all vegetation variables 
    - some may be reset if state file present
  ********************************************/

  initialize_veg(veg_var[WET], veg_con, global_param, Nveg);
  if ( options.DIST_PRCP )
    initialize_veg(veg_var[DRY], veg_con, global_param, Nveg);

  /********************************************
    Initialize all lake variables 
  ********************************************/

  if ( options.LAKES ) {
    tmp_lake_idx = lake_con.lake_idx;
    if (tmp_lake_idx < 0) tmp_lake_idx = 0;
    ErrorFlag = initialize_lake(lake_var, lake_con, soil_con, &(cell[WET][tmp_lake_idx][0]), surf_temp, 0);
    if (ErrorFlag == ERROR) return(ErrorFlag);
  }

  /********************************************
    Initialize all spatial frost variables 
  ********************************************/

#if SPATIAL_FROST
  for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++ ) {
    if ( FROST_SUBAREAS == 1 ) soil_con->frost_fract[frost_area] = 1.;
    else if (FROST_SUBAREAS == 2 ) soil_con->frost_fract[frost_area] = 0.5;
    else {
      soil_con->frost_fract[frost_area] = 1. / (FROST_SUBAREAS - 1);
      if ( frost_area == 0 || frost_area == FROST_SUBAREAS-1 ) 
	soil_con->frost_fract[frost_area] /= 2.;
    }
  }
#endif // SPATIAL_FROST

  /********************************************************
    Compute grid cell fractions for all subareas used in 
    spatial distribution of soil frost routines.
  ********************************************************/

#if QUICK_FS
  if(options.FROZEN_SOIL) {

    /***********************************************************
      Prepare table of maximum unfrozen water content values
      - This linearizes the equation for maximum unfrozen water
        content, reducing computation time for the frozen soil
        model.
    ***********************************************************/

    for(lidx=0;lidx<options.Nlayer;lidx++) { 
      for(ii=0;ii<QUICK_FS_TEMPS;ii++) {
	Aufwc = maximum_unfrozen_water(temps[ii], 1.0, 
				       soil_con->bubble[lidx], 
				       soil_con->expt[lidx]);
	Bufwc = maximum_unfrozen_water(temps[ii+1], 1.0, 
				       soil_con->bubble[lidx], 
				       soil_con->expt[lidx]);
	soil_con->ufwc_table_layer[lidx][ii][0] 
	  = linear_interp(0., temps[ii], temps[ii+1], Aufwc, Bufwc);
	soil_con->ufwc_table_layer[lidx][ii][1] 
	  = (Bufwc - Aufwc) / (temps[ii+1] - temps[ii]);
      }
    }
  }  
#endif // QUICK_FS

  /************************************************************************
    CASE 1: Not using quick ground heat flux, and initial conditions files 
    provided
  ************************************************************************/

  if(options.INIT_STATE) {

#if EXCESS_ICE
    sum_mindepth = 0;
    sum_depth_pre = 0;
    for( lidx = 0; lidx < options.Nlayer; lidx++ ){
      tmp_mindepth = (float)(int)(soil_con->min_depth[lidx] * 1000 + 0.5) / 1000;	
      sum_mindepth += tmp_mindepth;
      sum_depth_pre += soil_con->depth[lidx];
    }
#endif

    read_initial_model_state(filep.init_state, prcp, global_param,  
			     Nveg, options.SNOW_BAND, cellnum, soil_con,
			     Ndist, *init_STILL_STORM, *init_DRY_TIME, lake_con);



#if EXCESS_ICE
    // calculate dynamic soil and veg properties if excess_ice is present
    sum_depth_post = 0;
    for( lidx = 0; lidx < options.Nlayer; lidx++ )
      sum_depth_post += soil_con->depth[lidx];
    if( sum_depth_post != sum_depth_pre) {
      /*update soil_con properties*/
      for( lidx = 0; lidx < options.Nlayer; lidx++ ) {
        soil_con->bulk_dens_min[lidx] *= (1.0-soil_con->effective_porosity[lidx])*soil_con->soil_density[lidx]/soil_con->bulk_density[lidx];
        if (soil_con->organic[layer] > 0)
          soil_con->bulk_dens_org[lidx] *= (1.0-soil_con->effective_porosity[lidx])*soil_con->soil_density[lidx]/soil_con->bulk_density[lidx];
	soil_con->bulk_density[lidx] = (1.0-soil_con->effective_porosity[lidx])*soil_con->soil_density[lidx]; 
	soil_con->max_moist[lidx] = soil_con->depth[lidx] * soil_con->effective_porosity[lidx] * 1000.;	
      } //loop for each soil layer      
      
      /********update remaining soil_con properties**********/
      /* update Maximum Infiltration for Upper Layers */
      if(options.Nlayer==2)
	soil_con->max_infil = (1.0+soil_con->b_infilt)*soil_con->max_moist[0];
      else
	soil_con->max_infil = (1.0+soil_con->b_infilt)*(soil_con->max_moist[0]+soil_con->max_moist[1]);
      
      /* Soil Layer Critical and Wilting Point Moisture Contents */
      for(lidx=0;lidx<options.Nlayer;lidx++) {//soil layer
	soil_con->Wcr[lidx]  = soil_con->Wcr_FRACT[lidx] * soil_con->max_moist[lidx];
	soil_con->Wpwp[lidx] = soil_con->Wpwp_FRACT[lidx] * soil_con->max_moist[lidx];
	if(soil_con->Wpwp[lidx] > soil_con->Wcr[lidx]) {
	  sprintf(ErrStr,"Updated wilting point moisture (%f mm) is greater than updated critical point moisture (%f mm) for layer %d.\n\tIn the soil parameter file, Wpwp_FRACT MUST be <= Wcr_FRACT.\n",
		  soil_con->Wpwp[lidx], soil_con->Wcr[lidx], lidx);
	  nrerror(ErrStr);
	}
	if(soil_con->Wpwp[lidx] < soil_con->resid_moist[lidx] * soil_con->depth[lidx] * 1000.) {
	  sprintf(ErrStr,"Updated wilting point moisture (%f mm) is less than updated residual moisture (%f mm) for layer %d.\n\tIn the soil parameter file, Wpwp_FRACT MUST be >= resid_moist / (1.0 - bulk_density/soil_density).\n",
		  soil_con->Wpwp[lidx], soil_con->resid_moist[lidx] * soil_con->depth[lidx] * 1000., lidx);
	  nrerror(ErrStr);
	}
      }      
      
      /* If BASEFLOW = NIJSSEN2001 then convert ARNO baseflow
	 parameters d1, d2, d3, and d4 to Ds, Dsmax, Ws, and c */
      if(options.BASEFLOW == NIJSSEN2001) {
	lidx = options.Nlayer-1;
	soil_con->Dsmax = soil_con->Dsmax_orig * 
	  pow((double)(1./(soil_con->max_moist[lidx]-soil_con->Ws_orig)), -soil_con->c) +
	  soil_con->Ds_orig * soil_con->max_moist[lidx];
	soil_con->Ds = soil_con->Ds_orig * soil_con->Ws_orig / soil_con->Dsmax_orig;
	soil_con->Ws = soil_con->Ws_orig/soil_con->max_moist[lidx];
      }
      
      /*********** update root fractions ***************/
      calc_root_fractions(veg_con, soil_con);
      
#if VERBOSE
      /* write changes to screen */
      fprintf(stderr,"Soil properties initialized from state file:\n");
      for(lidx=0;lidx<options.Nlayer;lidx++) {//soil layer
	fprintf(stderr,"\tFor layer %d:\n",lidx+1);
	fprintf(stderr,"\t\tDepth of soil layer = %.2f m.\n",soil_con->depth[lidx]);
	fprintf(stderr,"\t\tEffective porosity = %.2f.\n",soil_con->effective_porosity[lidx]);
	fprintf(stderr,"\t\tBulk density = %.2f kg/m^3.\n",soil_con->bulk_density[lidx]);
      }
      fprintf(stderr,"\tDamping depth = %.2f m.\n",soil_con->dp);
      if(sum_depth_post == sum_mindepth)
	fprintf(stderr,"\tExcess ice is no longer present in the soil column.\n");
#endif //VERBOSE

    }//updated initial conditions due to state file
#endif //EXCESS_ICE

    /******Check that soil moisture does not exceed maximum allowed************/
    for ( dist = 0; dist < Ndist; dist ++ ) {
      for ( veg = 0 ; veg <= Nveg ; veg++ ) {

        for( band = 0; band < options.SNOW_BAND; band++ ) {
	  for( lidx = 0; lidx < options.Nlayer; lidx++ ) {	  

	    if ( cell[dist][veg][band].layer[lidx].moist > soil_con->max_moist[lidx] ) {
              fprintf( stderr, "WARNING: Initial soil moisture (%f mm) exceeds maximum (%f mm) in layer %d for veg tile %d and snow band%d.  Resetting to maximum.\n", cell[dist][veg][band].layer[lidx].moist, soil_con->max_moist[lidx], lidx, veg, band );
#if SPATIAL_FROST
              for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++)
                cell[dist][veg][band].layer[lidx].ice[frost_area] *= soil_con->max_moist[lidx]/cell[dist][veg][band].layer[lidx].moist;
#else
              cell[dist][veg][band].layer[lidx].ice *= soil_con->max_moist[lidx]/cell[dist][veg][band].layer[lidx].moist;
#endif
              cell[dist][veg][band].layer[lidx].moist = soil_con->max_moist[lidx];
	    }

#if SPATIAL_FROST
            for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++) {
              if (cell[dist][veg][band].layer[lidx].ice[frost_area] > cell[dist][veg][band].layer[lidx].moist)
                cell[dist][veg][band].layer[lidx].ice[frost_area] = cell[dist][veg][band].layer[lidx].moist;
            }
#else
            if (cell[dist][veg][band].layer[lidx].ice > cell[dist][veg][band].layer[lidx].moist)
              cell[dist][veg][band].layer[lidx].ice = cell[dist][veg][band].layer[lidx].moist;
#endif
            tmp_moist[lidx] = cell[dist][veg][band].layer[lidx].moist;

	  }
          compute_runoff_and_asat(soil_con, tmp_moist, 0, &(cell[dist][veg][band].asat), &tmp_runoff);
	}

        // Override possible bad values of soil moisture under lake coming from state file
        // (ideally we wouldn't store these in the state file in the first place)
        if (options.LAKES && veg == lake_con.lake_idx) {
          for( lidx = 0; lidx < options.Nlayer; lidx++ ) {
            lake_var->soil.layer[lidx].moist = soil_con->max_moist[lidx];
#if SPATIAL_FROST
            for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++) {
              if (lake_var->soil.layer[lidx].ice[frost_area] > lake_var->soil.layer[lidx].moist)
                lake_var->soil.layer[lidx].ice[frost_area] = lake_var->soil.layer[lidx].moist;
            }
#else
            if (lake_var->soil.layer[lidx].ice > lake_var->soil.layer[lidx].moist)
              lake_var->soil.layer[lidx].ice = lake_var->soil.layer[lidx].moist;
#endif
          }
	}
      }
    }


    /****** initialize moist and ice ************/
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;
      
      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {
	  for( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    moist[veg][band][lidx] = cell[0][veg][band].layer[lidx].moist;

#if SPATIAL_FROST
	    for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++ )
	      ice[veg][band][lidx][frost_area] = cell[0][veg][band].layer[lidx].ice[frost_area];
#else
	    ice[veg][band][lidx] = cell[0][veg][band].layer[lidx].ice;
#endif
	  }
	}
      }
    }

    /******Check that snow pack terms are self-consistent************/
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      for ( band = 0 ; band < options.SNOW_BAND ; band++ ) {
        if (snow[veg][band].swq > MAX_SURFACE_SWE) {
          pack_swq = snow[veg][band].swq-MAX_SURFACE_SWE;
          surf_swq = MAX_SURFACE_SWE;
        }
        else {
          pack_swq = 0;
          surf_swq = snow[veg][band].swq;
          snow[veg][band].pack_temp = 0;
        }
        if (snow[veg][band].surf_water > LIQUID_WATER_CAPACITY*surf_swq) {
          snow[veg][band].pack_water += snow[veg][band].surf_water - (LIQUID_WATER_CAPACITY*surf_swq);
          snow[veg][band].surf_water = LIQUID_WATER_CAPACITY*surf_swq;
        }
        if (snow[veg][band].pack_water > LIQUID_WATER_CAPACITY*pack_swq) {
          snow[veg][band].pack_water = LIQUID_WATER_CAPACITY*pack_swq;
        }
      }
    }

  }
  
  /************************************************************************
    CASE 2: Initialize soil if using quick heat flux, and no initial
    soil properties file given
  ************************************************************************/
    
  else if(options.QUICK_FLUX) {
    Nnodes = options.Nnode;

    /* Initialize soil node thicknesses */
    soil_con->dz_node[0]   = soil_con->depth[0];
    soil_con->dz_node[1]   = soil_con->depth[0];
    soil_con->dz_node[2]   = 2. * (dp - 1.5 * soil_con->depth[0]);    
    soil_con->Zsum_node[0] = 0;
    soil_con->Zsum_node[1] = soil_con->depth[0];
    soil_con->Zsum_node[2] = dp;

    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;
      
      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {

	  /* Initialize soil node temperatures */
	  energy[veg][band].T[0] = surf_temp;
	  energy[veg][band].T[1] = surf_temp;
	  energy[veg][band].T[2] = soil_con->avg_temp;

	  /* Initialize soil layer moisture and ice contents */
	  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    moist[veg][band][lidx] = cell[0][veg][band].layer[lidx].moist;
#if SPATIAL_FROST
	    for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++ )
	      ice[veg][band][lidx][frost_area] = 0.;
#else
	    ice[veg][band][lidx] = 0.;
#endif
	  }
	}
      }
    }
  }

  /*****************************************************************
    CASE 3: Initialize Energy Balance Variables if not using quick
    ground heat flux, and no Initial Condition File Given 
  *****************************************************************/
  else if(!options.QUICK_FLUX) {
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;
      
      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {
	  
	  if(!options.EXP_TRANS){  
	    /* Initialize soil node temperatures and thicknesses 
	       Nodes set at surface, the depth of the first layer,
	       twice the depth of the first layer, and at the
	       damping depth.  Extra nodes are placed equal distance
	       between the damping depth and twice the depth of the
	       first layer. */
	    
	    soil_con->dz_node[0] = soil_con->depth[0];
	    soil_con->dz_node[1] = soil_con->depth[0];
	    soil_con->dz_node[2] = soil_con->depth[0];

	    soil_con->Zsum_node[0] = 0;
	    soil_con->Zsum_node[1] = soil_con[0].depth[0];
	    Zsum   = 2. * soil_con[0].depth[0];
	    soil_con->Zsum_node[2] = Zsum;
	    tmpdp  = dp - soil_con[0].depth[0] * 2.5;
	    tmpadj = 3.5;
	    for ( index = 3; index < Nnodes-1; index++ ) {
	      if ( FIRST_VEG ) {
		soil_con->dz_node[index] = tmpdp/(((double)Nnodes-tmpadj));
	      }
	      Zsum += (soil_con->dz_node[index]
		       +soil_con->dz_node[index-1])/2.;
	      soil_con->Zsum_node[index] = Zsum;
	    }
	    energy[veg][band].T[0] = surf_temp;
	    for ( index = 1; index < Nnodes; index++ ) {
	      energy[veg][band].T[index] = soil_con->avg_temp;
	    }
	    if ( FIRST_VEG ) {
	      FIRST_VEG = FALSE;
	      soil_con->dz_node[Nnodes-1] = (dp - Zsum 
					     - soil_con->dz_node[Nnodes-2] 
					     / 2. ) * 2.;
	      Zsum += (soil_con->dz_node[Nnodes-2]
		       +soil_con->dz_node[Nnodes-1])/2.;
	      soil_con->Zsum_node[Nnodes-1] = Zsum;
	      if((int)(Zsum*1000+0.5) != (int)(dp*1000+0.5)) {
		sprintf(ErrStr,"Sum of thermal node thicknesses (%f) in initialize_model_state do not equal dp (%f), check initialization procedure",Zsum,dp);
		nrerror(ErrStr);
	      }
	    }
	  }
	  else{ /* exponential grid transformation, EXP_TRANS = TRUE*/
	    
	    if ( FIRST_VEG ) {
	      /*calculate exponential function parameter */
	      Bexp = logf(dp+1.)/(double)(Nnodes-1); //to force Zsum=dp at bottom node
              /* validate Nnodes by requiring that there be at least 3 nodes in the top 50cm */
              if (Nnodes < 5*logf(dp+1.)+1) {
		sprintf(ErrStr,"The number of soil thermal nodes (%d) is too small for the supplied damping depth (%f) with EXP_TRANS set to TRUE, leading to fewer than 3 nodes in the top 50 cm of the soil column.  For EXP_TRANS=TRUE, Nnodes and dp must follow the relationship:\n5*ln(dp+1)<Nnodes-1\nEither set Nnodes to at least %d in the global param file or reduce damping depth to %f in the soil parameter file.  Or set EXP_TRANS to FALSE in the global parameter file.",Nnodes,dp,(int)(5*logf(dp+1.))+2,exp(0.2*(Nnodes-1))+1);
		nrerror(ErrStr);
              }
 
	      for ( index = 0; index <= Nnodes-1; index++ )
		soil_con->Zsum_node[index] = expf(Bexp*index)-1.;
	      if(soil_con->Zsum_node[0] > soil_con->depth[0]) {
		sprintf(ErrStr,"Depth of first thermal node (%f) in initialize_model_state is greater than depth of first soil layer (%f); increase the number of nodes or decrease the thermal damping depth dp (%f)",soil_con->Zsum_node[0],soil_con->depth[0],dp);
		nrerror(ErrStr);
	      }
	    }	    
	    
	    //top node	  
	    index=0;
	    if ( FIRST_VEG )
	      soil_con->dz_node[index] = soil_con->Zsum_node[index+1]-soil_con->Zsum_node[index];
	    energy[veg][band].T[index] = surf_temp;
	    //middle nodes
	    for ( index = 1; index < Nnodes-1; index++ ) {
	      if ( FIRST_VEG ) {
		soil_con->dz_node[index] = (soil_con->Zsum_node[index+1]-soil_con->Zsum_node[index])/2.+(soil_con->Zsum_node[index]-soil_con->Zsum_node[index-1])/2.;
	      }
//	      energy[veg][band].T[index] = exp_interp(soil_con->Zsum_node[index],0.,soil_con[0].dp,
//						      surf_temp,soil_con[0].avg_temp);
              energy[veg][band].T[index] = soil_con->avg_temp;
	    }
	    //bottom node
	    index=Nnodes-1;
	    if ( FIRST_VEG )
	      soil_con->dz_node[index] = soil_con->Zsum_node[index]-soil_con->Zsum_node[index-1];
	    energy[veg][band].T[index] = soil_con->avg_temp;

	  } // end if !EXP_TRANS
	  
	  //initialize moisture and ice for each soil layer
	  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	    moist[veg][band][lidx] = cell[0][veg][band].layer[lidx].moist;
#if SPATIAL_FROST
	    for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++ )
	      ice[veg][band][lidx][frost_area] = 0.;
#else
	    ice[veg][band][lidx] = 0.;
#endif
	  }
	}
      }
    }
  }

  /*********************************
    CASE 4: Unknown option
  *********************************/
  else {
    for ( veg = 0 ; veg <= Nveg ; veg++ ) {
      // Initialize soil for existing vegetation types
      Cv = veg_con[veg].Cv;

      if ( Cv > 0 ) {
	for( band = 0; band < options.SNOW_BAND; band++ ) {
	  // Initialize soil for existing snow elevation bands
	  if ( soil_con->AreaFract[band] > 0. ) {	  
	    for ( index = 0; index < options.Nlayer; index++ ) {
	      soil_con->dz_node[index] = 1.;
	    }
	  }
	}
      }
    }
  }

  /********************************************
    Initialize subsidence 
  ********************************************/

#if EXCESS_ICE
  for ( lidx = 0; lidx < options.Nlayer; lidx++ ) 
    soil_con->subsidence[lidx] = 0.0;
    
#endif // EXCESS_ICE

  /******************************************
    Initialize soil thermal node properties 
  ******************************************/

  FIRST_VEG = TRUE;
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    // Initialize soil for existing vegetation types
    Cv = veg_con[veg].Cv;

    if ( Cv > 0 ) {
      for( band = 0; band < options.SNOW_BAND; band++ ) {
	// Initialize soil for existing snow elevation bands
	if ( soil_con->AreaFract[band] > 0. ) {
	    
	  /** Set soil properties for all soil nodes **/
	  if(FIRST_VEG) {
	    FIRST_VEG = FALSE;
	    set_node_parameters(soil_con->dz_node, soil_con->Zsum_node, soil_con->max_moist_node,
				soil_con->expt_node, soil_con->bubble_node,
				soil_con->alpha, soil_con->beta,
				soil_con->gamma, soil_con->depth,
				soil_con->max_moist, soil_con->expt, 
				soil_con->bubble, soil_con->quartz, 
#if QUICK_FS
				soil_con->ufwc_table_node,
#endif // QUICK_FS
#if EXCESS_ICE
				soil_con->porosity, soil_con->effective_porosity,
				soil_con->porosity_node, soil_con->effective_porosity_node,
#endif // EXCESS_ICE
				Nnodes, options.Nlayer, soil_con->FS_ACTIVE);	  
	  }
	
	  /* set soil moisture properties for all soil thermal nodes */
	  ErrorFlag = distribute_node_moisture_properties(energy[veg][band].moist,
						energy[veg][band].ice,
						energy[veg][band].kappa_node,
						energy[veg][band].Cs_node,
						soil_con->Zsum_node,
						energy[veg][band].T,
						soil_con->max_moist_node,
#if QUICK_FS
						soil_con->ufwc_table_node,
#else
						soil_con->expt_node,
						soil_con->bubble_node,
#endif // QUICK_FS
#if EXCESS_ICE
						soil_con->porosity_node,
						soil_con->effective_porosity_node,
#endif // EXCESS_ICE
						moist[veg][band], 
						soil_con->depth,
						soil_con->soil_dens_min,
						soil_con->bulk_dens_min,
						soil_con->quartz,
						soil_con->soil_density,
						soil_con->bulk_density,
						soil_con->organic,
						Nnodes, options.Nlayer,
						soil_con->FS_ACTIVE);
	  if ( ErrorFlag == ERROR ) return ( ErrorFlag );

          /* Check node spacing v time step */
          /* (note this is only approximate since heat capacity and conductivity can change considerably during the simulation depending on soil moisture and ice content) */
          if ((options.FROZEN_SOIL && !options.QUICK_FLUX) && !options.IMPLICIT) {
            dt_thresh = 0.5*energy[veg][band].Cs_node[1]/energy[veg][band].kappa_node[1]*pow((soil_con->dz_node[1]),2)/3600; // in hours
            if (global_param->dt > dt_thresh) {
              sprintf(ErrStr,"ERROR: You are currently running FROZEN SOIL with an explicit method (IMPLICIT is set to FALSE).  For the explicit method to be stable, time step %d hours is too large for the given thermal node spacing %f m, soil heat capacity %f J/m3/K, and soil thermal conductivity %f J/m/s/K.  Either set IMPLICIT to TRUE in your global parameter file (this is the recommended action), or decrease time step length to <= %f hours, or decrease the number of soil thermal nodes.",global_param->dt,soil_con->dz_node[1],energy[veg][band].Cs_node[1],energy[veg][band].kappa_node[1],dt_thresh);
              nrerror(ErrStr);
            }
          }

	  /* initialize layer moistures and ice contents */
	  for ( dry = 0; dry < Ndist; dry++ ) {
	    for ( lidx = 0; lidx < options.Nlayer; lidx++ ) {
	      cell[dry][veg][band].layer[lidx].moist = moist[veg][band][lidx];
#if SPATIAL_FROST
	      for ( frost_area = 0; frost_area < FROST_SUBAREAS; frost_area++ )

		cell[dry][veg][band].layer[lidx].ice[frost_area] = ice[veg][band][lidx][frost_area];
#else
	      cell[dry][veg][band].layer[lidx].ice = ice[veg][band][lidx];
#endif
	    }
            if (options.QUICK_FLUX) {
              ErrorFlag = estimate_layer_ice_content_quick_flux(cell[dry][veg][band].layer,
					   soil_con->depth, soil_con->dp,
					   energy[veg][band].T[0], energy[veg][band].T[1],
					   soil_con->avg_temp, soil_con->max_moist, 
#if QUICK_FS
					   soil_con->ufwc_table_layer,
#else
					   soil_con->expt, soil_con->bubble, 
#endif // QUICK_FS
#if SPATIAL_FROST
					   soil_con->frost_fract, soil_con->frost_slope, 
#endif // SPATIAL_FROST
#if EXCESS_ICE
					   soil_con->porosity,
					   soil_con->effective_porosity,
#endif // EXCESS_ICE
					   soil_con->FS_ACTIVE);
            }
            else {
	      ErrorFlag = estimate_layer_ice_content(cell[dry][veg][band].layer,
						       soil_con->Zsum_node,
						       energy[veg][band].T,
						       soil_con->max_moist_node,
#if QUICK_FS
						       soil_con->ufwc_table_node,
#else
						       soil_con->expt_node,
						       soil_con->bubble_node,
#endif // QUICK_FS
						       soil_con->depth,
						       soil_con->max_moist,
#if QUICK_FS
						       soil_con->ufwc_table_layer,
#else
						       soil_con->expt,
						       soil_con->bubble,
#endif // QUICK_FS
#if SPATIAL_FROST
						       soil_con->frost_fract, 
						       soil_con->frost_slope, 
#endif // SPATIAL_FROST
#if EXCESS_ICE
						       soil_con->porosity,
						       soil_con->effective_porosity,
#endif // EXCESS_ICE
						       Nnodes, options.Nlayer, 
						       soil_con->FS_ACTIVE);
		
	    }
	  }
	    
	  /* Find freezing and thawing front depths */
	  if(!options.QUICK_FLUX && soil_con->FS_ACTIVE) 
	    find_0_degree_fronts(&energy[veg][band], soil_con->Zsum_node, energy[veg][band].T, Nnodes);
	}
      }
    }
  }	

  // initialize miscellaneous energy balance terms
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    for ( band = 0; band < options.SNOW_BAND; band++ ) {
      /* Set fluxes to 0 */
      energy[veg][band].advected_sensible = 0.0;
      energy[veg][band].advection         = 0.0;
      energy[veg][band].AtmosError        = 0.0;
      energy[veg][band].AtmosLatent       = 0.0;
      energy[veg][band].AtmosLatentSub    = 0.0;
      energy[veg][band].AtmosSensible     = 0.0;
      energy[veg][band].canopy_advection  = 0.0;
      energy[veg][band].canopy_latent     = 0.0;
      energy[veg][band].canopy_latent_sub = 0.0;
      energy[veg][band].canopy_refreeze   = 0.0;
      energy[veg][band].canopy_sensible   = 0.0;
      energy[veg][band].deltaCC           = 0.0;
      energy[veg][band].deltaH            = 0.0;
      energy[veg][band].error             = 0.0;
      energy[veg][band].fusion            = 0.0;
      energy[veg][band].grnd_flux         = 0.0;
      energy[veg][band].latent            = 0.0;
      energy[veg][band].latent_sub        = 0.0;
      energy[veg][band].longwave          = 0.0;
      energy[veg][band].LongOverIn        = 0.0;
      energy[veg][band].LongUnderIn       = 0.0;
      energy[veg][band].LongUnderOut      = 0.0;
      energy[veg][band].melt_energy       = 0.0;
      energy[veg][band].NetLongAtmos      = 0.0;
      energy[veg][band].NetLongOver       = 0.0;
      energy[veg][band].NetLongUnder      = 0.0;
      energy[veg][band].NetShortAtmos     = 0.0;
      energy[veg][band].NetShortGrnd      = 0.0;
      energy[veg][band].NetShortOver      = 0.0;
      energy[veg][band].NetShortUnder     = 0.0;
      energy[veg][band].out_long_canopy   = 0.0;
      energy[veg][band].out_long_surface  = 0.0;
      energy[veg][band].refreeze_energy   = 0.0;
      energy[veg][band].sensible          = 0.0;
      energy[veg][band].shortwave         = 0.0;
      energy[veg][band].ShortOverIn       = 0.0;
      energy[veg][band].ShortUnderIn      = 0.0;
      energy[veg][band].snow_flux         = 0.0;
      /* Initial estimate of LongUnderOut for use by snow_intercept() */
      tmp = energy[veg][band].T[0] + KELVIN;
      energy[veg][band].LongUnderOut = STEFAN_B * tmp * tmp * tmp * tmp;
      energy[veg][band].Tfoliage     = Tair + soil_con->Tfactor[band];
    }
  }

  // initialize Tfallback counters
  for ( veg = 0 ; veg <= Nveg ; veg++) {
    for ( band = 0; band < options.SNOW_BAND; band++ ) {
      energy[veg][band].Tfoliage_fbcount = 0;
      energy[veg][band].Tcanopy_fbcount = 0;
      energy[veg][band].Tsurf_fbcount = 0;
      for ( index = 0; index < Nnodes-1; index++ ) {
	energy[veg][band].T_fbcount[index] = 0;
      }
    }
  }

  // Compute treeline adjustment factors
  for ( band = 0; band < options.SNOW_BAND; band++ ) {
    if ( soil_con->AboveTreeLine[band] ) {
      Cv = 0;
      for ( veg = 0 ; veg < veg_con[0].vegetat_type_num ; veg++ ) {
        if ( veg_lib[veg_con[veg].veg_class].overstory )
          Cv += veg_con[veg].Cv;
      }
      TreeAdjustFactor[band] = 1. / ( 1. - Cv );
    }
    else TreeAdjustFactor[band] = 1.;
  }

  return(0);
}
Beispiel #6
0
int  runoff(cell_data_struct  *cell,
            energy_bal_struct *energy,
            soil_con_struct   *soil_con,
	    double             ppt, 
	    double            *frost_fract,
	    int                dt,
            int                Nnodes,
	    int                band,
	    int                rec,
	    int                iveg)
/**********************************************************************
	runoff.c	Keith Cherkauer		May 18, 1996

  This subroutine calculates infiltration and runoff from the surface,
  gravity driven drainage between all soil layers, and generates 
  baseflow from the bottom layer..
  
  sublayer indecies are always [layer number][sublayer number]
  [layer number] is the current VIC model moisture layer
  [sublayer number] is the current sublayer number where: 
         0 = thawed sublayer, 1 = frozen sublayer, and 2 = unfrozen sublayer.
	 when the model is run withoputfrozen soils, the sublayer number
	 is always = 2 (unfrozen).

  UNITS:	Ksat (mm/day)
		Q12  (mm/time step)
		liq, ice (mm)
		inflow (mm)
                runoff (mm)

  Variables:
	ppt	incoming precipitation and snow melt
	mu	fraction of area that receives precipitation
	inflow	incoming water corrected for fractional area of precip (mu)

  MODIFICATIONS:
  5/22/96 Routine modified to account for spatially varying
	  precipitation, and it's effects on runoff.	KAC
  11/96	  Code modified to account for extra model layers
  	  needed for frozen soils modeling.		KAC
  1/9/97  Infiltration and other rate parameters modified
	  for time scales of less than 1 day.		KAC
  4-1-98  Soil moisture transport is now done on an hourly time
          step, irregardless to the model time step, to prevent
          numerical stabilities in the solution	Dag and KAC
  01-24-00 simplified handling of soil moisture for the
           frozen soil algorithm.  all option selection
	   now use the same soil moisture transport method   KAC
  6-8-2000 modified to handle spatially distributed soil frost  KAC
  06-07-03 modified so that infiltration is computed using only the
           top two soil moisture layers, rather than all but the
           bottom most layer.  This preserves the functionality
           of the original model design, but is more realistic for
           handling multiple soil moisture layers
  06-Sep-03   Changed calculation of dt_baseflow to go to zero when
              soil liquid moisture <= residual moisture.  Changed
              block that handles case of total soil moisture < residual
              moisture to not allow dt_baseflow to go negative.		TJB
  17-May-04   Changed block that handles baseflow when soil moisture
	      drops below residual moisture.  Now, the block is only
	      entered if baseflow > 0 and soil moisture < residual,
	      and the amount of water taken out of baseflow and given
	      to the soil cannot exceed baseflow.  In addition, error
	      messages are no longer printed, since it isn't an error
	      to be in that block.					TJB
  2007-Apr-04 Modified to return Error status from 
              distribute_node_moisture_properties			GCT/KAC
  2007-Apr-24 Passes soil_con->Zsum_node to distribute_node_moisture_properties.  JCA
  2007-Jun-13 Fixed bug arising from earlier fix to dt_baseflow
	      calculation.  Earlier fix took residual moisture
	      into account in the linear part of the baseflow eqn,
	      but not in the non-linear part.  Now we take residual
	      moisture into account correctly throughout the whole
	      equation.  Also re-wrote equation in simpler form.	TJB
  2007-Aug-15 Changed SPATIAL_FROST if statement to enclose the correct
              end-bracket for the frost_area loop.			JCA
  2007-Aug-09 Added features for EXCESS_ICE option.			JCA
              Including adding SubsidenceUpdate flag for parts
              of the routine that will be used if redistributing
              soil moisture after subsidence.
  2007-Sep-18 Modified to correctly handle evaporation from spatially
	      distributed soil frost.  Original version could produce
	      negative soil moisture in fractions with high ice content
	      since only total evaporation was checked versus total
	      liquid water content, not versus available liquid water
	      in each frost subsection.					KAC via TJB
  2007-Sep-20 Removed logic that reset resid_moist[i].  Previously,
	      resid_moist[i] was reset to 0 for i > 0 when
	      resid_moist[0] == 0.  Such resetting of soil properties
	      was deemed unnecessary and confusing, since VIC would end
	      up using different residual moisture values than those
	      specified by the user.  If a user truly wants to specify
	      residual moisture in all layers to be 0, the user should
	      set these explicitly in the soil parameter file.  Also
	      fixed typo in fprintf() on line 289.			TJB
  2007-Oct-13 Fixed the checks on the lower bound of soil moisture.
	      Previously, the condition was
	        (moist[lindex]+ice[lindex]) < resid_moist[lindex]
	      which led to liquid soil moisture falling below residual
	      during winter conditions.  This has been changed to
	        moist[lindex] < resid_moist[lindex]
	      to eliminate these errors and make the logic consistent
	      with the rest of the code.				TJB
  2007-Oct-13 Renamed all *moist* variables to *liq* if they only refer
	      to liquid soil moisture.  This makes the logic much easier
	      to understand.						TJB
  2007-Oct-13 Modified the caps on Q12 and baseflow for the case of
	      frozen soil.  Now, the lower bound on liquid soil moisture
	      is the maximum unfrozen component of residual moisture at
	      current soil temperature, i.e.  liquid soil moisture may
	      be less than residual moisture as long as the total
	      (liq + ice) moisture is >= residual moisture AND the
	      liquid fraction of the total is appropriate for the
	      temperature.  Without this condition, we could have an
	      apparent loss of liquid moisture due to conversion to ice
	      and the resulting adjustments of Q12 and baseflow could
	      pull water out of the air to bring liquid moisture up to
	      residual.  This fix should set a reasonable lower bound
	      and still ensure that no extra water is condensed out
	      of the air simply to bring liquid water up to residual.	TJB
  2008-Oct-23 Added check to make sure top_moist never exceeds
	      top_max_moist; otherwise rounding errors could cause it
	      to exceed top_max_moist and produce NaN's.		LCB via TJB
  2009-Feb-09 Removed dz_node from call to
	      distribute_node_moisture_properties.			KAC via TJB
  2009=Feb-10 Replaced all occurrences of resid_moist with min_liq, after 
	      min_liq was defined.  This makes the use of min_liq consistent 
	      with its documented role in the subroutine.		KAC via TJB
  2009-Feb-10 Removed Tlayer from selection criteria to include ice in
	      min_liq calculation.  Soil layers can be above 0C with
	      ice present, as ice content is set from soil nodes.	KAC via TJB
  2009-Mar-16 Made min_liq an element of the layer_data_struct, so that
	      its value can be computed earlier in the model code, in a
	      more efficient manner (in initialize_soil() and
	      estimate_layer_ice_content()).				TJB
  2009-May-17 Added asat to cell_data.					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-Dec-11 Removed min_liq and options.MIN_LIQ.  Constraints on
	      liq[lindex] have been removed and/or replaced by
	      constraints on (liq[lindex]+ice[lindex]).  Thus, it is
	      possible to freeze all of the soil moisture, as long as
	      total moisture > residual moisture.				TJB
  2010-Feb-07 Fixed bug in runoff computation for case when soil column
	      is completely saturated.						TJB
  2010-Nov-29 Moved computation of saturated area to correct place in
	      code for handling SPATIAL_FROST.					TJB
  2010-Dec-01 Added call to compute_zwt().					TJB
  2011-Mar-01 Replaced compute_zwt() with wrap_compute_zwt().  Moved
	      computation of runoff and saturated area to a separate
	      function compute_runoff_and_asat(), which can be called
	      elsewhere.							TJB
  2011-Jun-03 Added options.ORGANIC_FRACT.  Soil properties now take
	      organic fraction into account.					TJB
  2012-Jan-16 Removed LINK_DEBUG code						BN
  2013-Dec-26 Replaced LOW_RES_MOIST compile-time option with LOG_MATRIC 
	      run-time option.							TJB
  2013-Dec-26 Removed EXCESS_ICE option.					TJB
  2013-Dec-27 Moved SPATIAL_FROST to options_struct.				TJB
  2013-Dec-27 Removed QUICK_FS option.						TJB
  2014-Mar-28 Removed DIST_PRCP option.						TJB
  2014-May-09 Added check on liquid soil moisture to ensure always >= 0.	TJB
**********************************************************************/
{  
  extern option_struct options;
  int                firstlayer, lindex;
  int                i;
  int                last_layer[MAX_LAYERS*3];
  int                last_index;
  int                last_cnt;
  int                time_step;
  int                tmplayer;
  int                frost_area;
  int                ErrorFlag;
  double             A, frac;
  double             tmp_runoff;
  double             inflow;
  double             resid_moist[MAX_LAYERS]; // residual moisture (mm)
  double             org_moist[MAX_LAYERS];   // total soil moisture (liquid and frozen) at beginning of this function (mm)
  double             avail_liq[MAX_LAYERS][MAX_FROST_AREAS]; // liquid soil moisture available for evap/drainage (mm)
  double             liq[MAX_LAYERS];         // current liquid soil moisture (mm)
  double             ice[MAX_LAYERS];         // current frozen soil moisture (mm)
  double             moist[MAX_LAYERS];       // current total soil moisture (liquid and frozen) (mm)
  double             max_moist[MAX_LAYERS];   // maximum storable moisture (liquid and frozen) (mm)
  double             Ksat[MAX_LAYERS];
  double             Q12[MAX_LAYERS-1];
  double             Dsmax;
  double             tmp_inflow;
  double             tmp_moist;
  double             tmp_moist_for_runoff[MAX_LAYERS];
  double             tmp_liq;
  double             dt_inflow;
  double             dt_runoff;
  double             runoff[MAX_FROST_AREAS];
  double             tmp_dt_runoff[MAX_FROST_AREAS];
  double             baseflow[MAX_FROST_AREAS];
  double             dt_baseflow;
  double             rel_moist;
  double             evap[MAX_LAYERS][MAX_FROST_AREAS];
  double             sum_liq;
  double             evap_fraction;
  double             evap_sum;
  double             min_temp;
  double             max_temp;
  double             tmp_fract;
  double             Tlayer_spatial[MAX_LAYERS][MAX_FROST_AREAS];
  double             b[MAX_LAYERS];
  layer_data_struct *layer;
  layer_data_struct  tmp_layer;

  /** Set Residual Moisture **/
  for ( i = 0; i < options.Nlayer; i++ ) 
    resid_moist[i] = soil_con->resid_moist[i] * soil_con->depth[i] * 1000.;

  /** Allocate and Set Values for Soil Sublayers **/
  layer = cell->layer;

  cell->runoff = 0;
  cell->baseflow = 0;
  cell->asat = 0;

  for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ )
    baseflow[frost_area] = 0;
      
  for ( lindex = 0; lindex < options.Nlayer; lindex++ ) {
    evap[lindex][0] = layer[lindex].evap/(double)dt;
    org_moist[lindex] = layer[lindex].moist;
    layer[lindex].moist = 0;
    if ( evap[lindex][0] > 0 ) { // if there is positive evaporation
      sum_liq = 0;
      // compute available soil moisture for each frost sub area.
      for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ ) {
        avail_liq[lindex][frost_area] = (org_moist[lindex] - layer[lindex].ice[frost_area] - resid_moist[lindex]);
        if (avail_liq[lindex][frost_area] < 0) avail_liq[lindex][frost_area] = 0;
        sum_liq += avail_liq[lindex][frost_area]*frost_fract[frost_area];
      }
      // compute fraction of available soil moisture that is evaporated
      if (sum_liq > 0) {
        evap_fraction = evap[lindex][0] / sum_liq;
      }
      else {
        evap_fraction = 1.0;
      }
      // distribute evaporation between frost sub areas by percentage
      evap_sum = evap[lindex][0];
      for ( frost_area = options.Nfrost - 1; frost_area >= 0; frost_area-- ) {
        evap[lindex][frost_area] = avail_liq[lindex][frost_area] * evap_fraction;
        avail_liq[lindex][frost_area] -= evap[lindex][frost_area];
        evap_sum -= evap[lindex][frost_area] * frost_fract[frost_area];
      }
    }
    else {
      for ( frost_area = options.Nfrost - 1; frost_area > 0; frost_area-- )
        evap[lindex][frost_area] = evap[lindex][0];
    }
  }

  // compute temperatures of frost subareas
  for ( lindex = 0; lindex < options.Nlayer; lindex++ ) {
    min_temp = layer[lindex].T - soil_con->frost_slope / 2.;
    max_temp = min_temp + soil_con->frost_slope;
    for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ ) {
      if ( options.Nfrost > 1 ) {
        if ( frost_area == 0 ) tmp_fract = frost_fract[0] / 2.;
        else tmp_fract += (frost_fract[frost_area-1] + frost_fract[frost_area]) / 2.;
        Tlayer_spatial[lindex][frost_area] = linear_interp(tmp_fract, 0, 1, min_temp, max_temp);
      }
      else Tlayer_spatial[lindex][frost_area] = layer[lindex].T;
    }
  }

  for ( frost_area = 0; frost_area < options.Nfrost; frost_area++ ) {

    /** ppt = amount of liquid water coming to the surface **/
    inflow = ppt;
	
    /**************************************************
      Initialize Variables
    **************************************************/
    for ( lindex = 0; lindex < options.Nlayer; lindex++ ) {
      Ksat[lindex]         = soil_con->Ksat[lindex] / 24.;
      b[lindex]            = (soil_con->expt[lindex] - 3.) / 2.;

      /** Set Layer Liquid Moisture Content **/
      liq[lindex] = org_moist[lindex] - layer[lindex].ice[frost_area];

      /** Set Layer Frozen Moisture Content **/
      ice[lindex]       = layer[lindex].ice[frost_area];

      /** Set Layer Maximum Moisture Content **/
      max_moist[lindex] = soil_con->max_moist[lindex];

    } // initialize variables for each layer

    /******************************************************
      Runoff Based on Soil Moisture Level of Upper Layers
    ******************************************************/

    for(lindex=0;lindex<options.Nlayer;lindex++) {
      tmp_moist_for_runoff[lindex] = (liq[lindex] + ice[lindex]);
    }
    compute_runoff_and_asat(soil_con, tmp_moist_for_runoff, inflow, &A, &(runoff[frost_area]));

    // save dt_runoff based on initial runoff estimate,
    // since we will modify total runoff below for the case of completely saturated soil
    tmp_dt_runoff[frost_area] = runoff[frost_area] / (double) dt;
	  
    /**************************************************
      Compute Flow Between Soil Layers (using an hourly time step)
    **************************************************/
	  
    dt_inflow  =  inflow / (double) dt;
	  
    for (time_step = 0; time_step < dt; time_step++) {
      inflow   = dt_inflow;
      last_cnt = 0;
	    
      /*************************************
        Compute Drainage between Sublayers 
      *************************************/

      for( lindex = 0; lindex < options.Nlayer-1; lindex++ ) {

        /** Brooks & Corey relation for hydraulic conductivity **/
	      
        if((tmp_liq = liq[lindex] - evap[lindex][frost_area]) < resid_moist[lindex])
	  tmp_liq = resid_moist[lindex];
	      
	if(liq[lindex] > resid_moist[lindex]) {
	  Q12[lindex] = Ksat[lindex] * pow(((tmp_liq - resid_moist[lindex]) / (soil_con->max_moist[lindex] - resid_moist[lindex])), soil_con->expt[lindex]); 
	}
	else Q12[lindex] = 0.;
	last_layer[last_cnt] = lindex;
      }
	    
      /**************************************************
        Solve for Current Soil Layer Moisture, and
        Check Versus Maximum and Minimum Moisture Contents.  
      **************************************************/
	    
      firstlayer = TRUE;
      last_index = 0;
      for ( lindex = 0; lindex < options.Nlayer - 1; lindex++ ) {
	      
        if ( lindex == 0 ) dt_runoff = tmp_dt_runoff[frost_area];
	else dt_runoff = 0;

	/* transport moisture for all sublayers **/

	tmp_inflow = 0.;
	      
	/** Update soil layer moisture content **/
	liq[lindex] = liq[lindex] + (inflow - dt_runoff) - (Q12[lindex] + evap[lindex][frost_area]);
	      
	/** Verify that soil layer moisture is less than maximum **/
	if((liq[lindex]+ice[lindex]) > max_moist[lindex]) {
	  tmp_inflow = (liq[lindex]+ice[lindex]) - max_moist[lindex];
	  liq[lindex] = max_moist[lindex] - ice[lindex];

          if(lindex==0) {
	    Q12[lindex] += tmp_inflow;
	    tmp_inflow = 0;
	  }
	  else {
	    tmplayer = lindex;
	    while(tmp_inflow > 0) {
	      tmplayer--;
	      if ( tmplayer < 0 ) {
		/** If top layer saturated, add to runoff **/
		runoff[frost_area] += tmp_inflow;
		tmp_inflow = 0;
	      }
	      else {
		/** else add excess soil moisture to next higher layer **/
		liq[tmplayer] += tmp_inflow;
		if((liq[tmplayer]+ice[tmplayer]) > max_moist[tmplayer]) {
		  tmp_inflow = ((liq[tmplayer] + ice[tmplayer]) - max_moist[tmplayer]);
		  liq[tmplayer] = max_moist[tmplayer] - ice[tmplayer];
		}
	        else tmp_inflow=0;
	      }
	    }
	  } /** end trapped excess moisture **/
	} /** end check if excess moisture in top layer **/
	      
	firstlayer=FALSE;
	      
	/** verify that current layer moisture is greater than minimum **/
	if (liq[lindex] < 0) {
	  /** liquid cannot fall below 0 **/
	  Q12[lindex] += liq[lindex];
	  liq[lindex] = 0;
	}
	if ((liq[lindex]+ice[lindex]) < resid_moist[lindex]) {
	  /** moisture cannot fall below minimum **/
	  Q12[lindex] += (liq[lindex]+ice[lindex]) - resid_moist[lindex];
	  liq[lindex] = resid_moist[lindex] - ice[lindex];
	}
	      
	inflow = (Q12[lindex]+tmp_inflow);
	Q12[lindex] += tmp_inflow;
	      
	last_index++;
	      
      } /* end loop through soil layers */
	    
      /**************************************************
        Compute Baseflow
      **************************************************/
	    
      /** ARNO model for the bottom soil layer (based on bottom
          soil layer moisture from previous time step) **/
	    
      lindex = options.Nlayer-1;
      Dsmax = soil_con->Dsmax / 24.;

      /** Compute relative moisture **/
      rel_moist = (liq[lindex]-resid_moist[lindex]) / (soil_con->max_moist[lindex]-resid_moist[lindex]);

      /** Compute baseflow as function of relative moisture **/
      frac = Dsmax * soil_con->Ds / soil_con->Ws;
      dt_baseflow = frac * rel_moist;
      if (rel_moist > soil_con->Ws) {
        frac = (rel_moist - soil_con->Ws) / (1 - soil_con->Ws);
        dt_baseflow += Dsmax * (1 - soil_con->Ds / soil_con->Ws) * pow(frac,soil_con->c);
      }
	    
      /** Make sure baseflow isn't negative **/
      if(dt_baseflow < 0) dt_baseflow = 0;
	    
      /** Extract baseflow from the bottom soil layer **/ 
	    
      liq[lindex] += Q12[lindex-1] - (evap[lindex][frost_area] + dt_baseflow);
	    
      /** Check Lower Sub-Layer Moistures **/
      tmp_moist = 0;

      /* If soil moisture has gone below minimum, take water out
       * of baseflow and add back to soil to make up the difference
       * Note: this may lead to negative baseflow, in which case we will
       * reduce evap to make up for it */
      if((liq[lindex]+ice[lindex]) < resid_moist[lindex]) {
        dt_baseflow += (liq[lindex]+ice[lindex]) - resid_moist[lindex];
        liq[lindex] = resid_moist[lindex] - ice[lindex];
      }

      if((liq[lindex]+ice[lindex]) > max_moist[lindex]) {
        /* soil moisture above maximum */
        tmp_moist = ((liq[lindex]+ice[lindex]) - max_moist[lindex]);
        liq[lindex] = max_moist[lindex] - ice[lindex];
        tmplayer = lindex;
        while(tmp_moist > 0) {
          tmplayer--;
          if(tmplayer<0) {
            /** If top layer saturated, add to runoff **/
            runoff[frost_area] += tmp_moist;
            tmp_moist = 0;
          }
          else {
            /** else if sublayer exists, add excess soil moisture **/
            liq[tmplayer] += tmp_moist ;
            if ( ( liq[tmplayer] + ice[tmplayer]) > max_moist[tmplayer] ) {
	      tmp_moist = ((liq[tmplayer] + ice[tmplayer]) - max_moist[tmplayer]);
	      liq[tmplayer] = max_moist[tmplayer] - ice[tmplayer];
            }
            else tmp_moist=0;
          }
        }
      }
	    
      baseflow[frost_area] += dt_baseflow;
	    
    } /* end of hourly time step loop */

    /** If negative baseflow, reduce evap accordingly **/
    if ( baseflow[frost_area] < 0 ) {
      layer[lindex].evap   += baseflow[frost_area];
      baseflow[frost_area]  = 0;
    }

    /** Recompute Asat based on final moisture level of upper layers **/
    for(lindex=0;lindex<options.Nlayer;lindex++) {
      tmp_moist_for_runoff[lindex] = (liq[lindex] + ice[lindex]);
    }
    compute_runoff_and_asat(soil_con, tmp_moist_for_runoff, 0, &A, &tmp_runoff);

    /** Store tile-wide values **/
    for ( lindex = 0; lindex < options.Nlayer; lindex++ ) 
      layer[lindex].moist += ((liq[lindex] + ice[lindex]) * frost_fract[frost_area]); 
    cell->asat     += A * frost_fract[frost_area];
    cell->runoff   += runoff[frost_area] * frost_fract[frost_area];
    cell->baseflow += baseflow[frost_area] * frost_fract[frost_area];

  }

  /** Compute water table depth **/
  wrap_compute_zwt(soil_con, cell);

  /** Recompute Thermal Parameters Based on New Moisture Distribution **/
  if(options.FULL_ENERGY || options.FROZEN_SOIL) {
    
    for(lindex=0;lindex<options.Nlayer;lindex++) {
      tmp_layer = cell->layer[lindex];
      moist[lindex] = tmp_layer.moist;
    }
    
    ErrorFlag = distribute_node_moisture_properties(energy->moist, energy->ice,
						    energy->kappa_node, energy->Cs_node,
						    soil_con->Zsum_node, energy->T,
						    soil_con->max_moist_node,
						    soil_con->expt_node,
						    soil_con->bubble_node, 
						    moist, soil_con->depth, 
						    soil_con->soil_dens_min,
						    soil_con->bulk_dens_min,
						    soil_con->quartz, 
						    soil_con->soil_density,
						    soil_con->bulk_density,
						    soil_con->organic, Nnodes, 
						    options.Nlayer, soil_con->FS_ACTIVE);
    if ( ErrorFlag == ERROR ) return (ERROR);
  }
  return (0);

}