Example #1
0
int main(int argc, char *argv[])
/**********************************************************************
	vicNl.c		Dag Lohmann		January 1996

  This program controls file I/O and variable initialization as well as
  being the primary driver for the model.

  For details about variables, input files and subroutines check:
	http://ce.washington.edu/~hydro/Lettenmaier/Models/VIC/VIC_home.html

  UNITS: unless otherwise marked:
         all water balance components are in mm
	 all energy balance components are in mks
	 depths, and lengths are in m

  modifications:
  1997-98 Model was updated from simple 2 layer water balance to 
          an extension of the full energy and water balance 3 layer
	  model.                                                  KAC
  02-27-01 added controls for lake model                          KAC
  11-18-02 Updated storage of lake water for water balance 
           calculations.                                          LCB
  03-12-03 Modifed to add AboveTreeLine to soil_con_struct so that
           the model can make use of the computed treeline.     KAC
  04-10-03 Modified to initialize storm parameters using the state
           file.                                                KAC
  04-10-03 Modified to start the model by skipping records until the
           state file date is found.  This replaces the previous method
           of modifying the global file start date, which can change 
           the interpolation of atmospheric forcing data.        KAC
  04-15-03 Modified to store wet and dry fractions when intializing 
           water balance storage.  This accounts for changes in model
           state initialization, which now stores wet and dry fractions
           rather than just averagedvalues.                      KAC
  29-Oct-03 Modified the version display banner to print the version
	    string defined in global.h.					TJB
  01-Nov-04 Updated arglist for make_dist_prcp(), as part of fix for
	    QUICK_FLUX state file compatibility.			TJB
  02-Nov-04 Updated arglist for read_lakeparam(), as part of fix for
	    lake fraction readjustment.					TJB
  2005-Apr-13 OUTPUT_FORCE option now calls close_files().		TJB
  2006-Sep-23 Implemented flexible output configuration; uses the new
              out_data, out_data_files, and save_data structures.	TJB
  2006-Oct-16 Merged infiles and outfiles structs into filep_struct;
	      This included merging builtnames into filenames.		TJB
  2006-Nov-07 Removed LAKE_MODEL option.				TJB
  2006-Nov-07 Changed statefile to init_state in call to
	      check_state_file().					TJB
  2007-Jan-15 Added PRT_HEADER option; added call to
	      write_header().						TJB
  2007-Apr-04 Added option to continue run after a cell fails. 		GCT/KAC
  2007-Apr-21 Added calls to free_dmy(), free_out_data_files(),
	      free_out_data(), and free_veglib().  Added closing of
	      all parameter files.					TJB
  2007-Aug-21 Return ErrorFlag from initialize_model_state.		JCA
  2007-Sep-14 Excluded calls to free_veglib() and closing of parameter
	      files other than the soil param file for the case
	      when OUTPUT_FORCE=TRUE.					TJB
  2007-Nov-06 Moved computation of cell_area from read_lakeparam() to
	      read_soilparam() and read_soilparam_arc().		TJB
  2008-May-05 Added prcp fraction (mu) to initial water storage
	      computation.  This solves water balance errors for the
	      case where DIST_PRCP is TRUE.				TJB
  2009-Jan-16 Added soil_con.avgJulyAirTemp to argument list of
	      initialize_atmos().					TJB
  2009-Jun-09 Modified to use extension of veg_lib structure to contain
	      bare soil information.					TJB
  2009-Jul-07 Added soil_con.BandElev[] to read_snowband() arg list.	TJB
  2009-Jul-31 Replaced references to N+1st veg tile with references
	      to index of lake/wetland tile.				TJB
  2009-Sep-28 Replaced initial water/energy storage computations and
	      calls to calc_water_balance_error/calc_energy_balance_error
	      with an initial call to put_data.  Modified the call to
	      read_snowband().						TJB
  2009-Dec-11 Removed save_data structure from argument list of 
	      initialize_model_state().					TJB
  2010-Mar-31 Added cell_area to initialize_atmos().			TJB
  2010-Apr-28 Removed individual soil_con variables from argument list
	      of initialize_atmos() and replaced with *soil_con.	TJB
  2010-Nov-10 Added closing of state files.				TJB
  2011-Jan-04 Made read_soilparam_arc() a sub-function of
	      read_soilparam().						TJB
  2012-Jan-16 Removed LINK_DEBUG code					BN
**********************************************************************/
{

  extern veg_lib_struct *veg_lib;
  extern option_struct options;
  extern Error_struct Error;
  extern global_param_struct global_param;

  /** Variable Declarations **/

  char                     NEWCELL;
  char                     LASTREC;
  char                     MODEL_DONE;
  char                     RUN_MODEL;
  char                    *init_STILL_STORM;
  char                     ErrStr[MAXSTRING];
  int                      rec, i, j;
  int                      veg;
  int                      dist;
  int                      band;
  int                      Ndist;
  int                      Nveg_type;
  int                      cellnum;
  int                      index;
  int                     *init_DRY_TIME;
  int                      Ncells;
  int                      cell_cnt;
  int                      startrec;
  int                      ErrorFlag;
  float                    mu;
  double                   storage;
  double                   veg_fract;
  double                   band_fract;
  double                   Clake;
  dmy_struct              *dmy;
  atmos_data_struct       *atmos;
  veg_con_struct          *veg_con;
  soil_con_struct          soil_con;
  dist_prcp_struct         prcp; /* stores information about distributed 
				    precipitation */
  filenames_struct         filenames;
  filep_struct             filep;
  lake_con_struct          lake_con;
  out_data_file_struct     *out_data_files;
  out_data_struct          *out_data;
  save_data_struct         save_data;
  
  /** Read Model Options **/
  initialize_global();
  filenames = cmd_proc(argc, argv);

#if VERBOSE
  display_current_settings(DISP_VERSION,(filenames_struct*)NULL,(global_param_struct*)NULL);
#endif

  /** Read Global Control File **/
  filep.globalparam = open_file(filenames.global,"r");
  global_param = get_global_param(&filenames, filep.globalparam);

  /** Set up output data structures **/
  out_data = create_output_list();
  out_data_files = set_output_defaults(out_data);
  fclose(filep.globalparam);
  filep.globalparam = open_file(filenames.global,"r");
  parse_output_info(&filenames, filep.globalparam, &out_data_files, out_data);

  /** Check and Open Files **/
  check_files(&filep, &filenames);

#if !OUTPUT_FORCE

  /** Read Vegetation Library File **/
  veg_lib = read_veglib(filep.veglib,&Nveg_type);

#endif // !OUTPUT_FORCE

  /** Initialize Parameters **/
  if(options.DIST_PRCP) Ndist = 2;
  else Ndist = 1;
  cellnum = -1;

  /** Make Date Data Structure **/
  dmy      = make_dmy(&global_param);

  /** allocate memory for the atmos_data_struct **/
  alloc_atmos(global_param.nrecs, &atmos);

  /** Initial state **/
  startrec = 0;
#if !OUTPUT_FORCE
  if ( options.INIT_STATE ) 
    filep.init_state = check_state_file(filenames.init_state, dmy, 
					 &global_param, options.Nlayer, 
					 options.Nnode, &startrec);

  /** open state file if model state is to be saved **/
  if ( options.SAVE_STATE && strcmp( filenames.statefile, "NONE" ) != 0 )
    filep.statefile = open_state_file(&global_param, filenames, options.Nlayer,
                                         options.Nnode);
  else filep.statefile = NULL;

#endif // !OUTPUT_FORCE

  /************************************
    Run Model for all Active Grid Cells
    ************************************/
  MODEL_DONE = FALSE;
  cell_cnt=0;
  while(!MODEL_DONE) {

    soil_con = read_soilparam(filep.soilparam, filenames.soil_dir, &cell_cnt, &RUN_MODEL, &MODEL_DONE);

    if(RUN_MODEL) {

#if QUICK_FS
      /** Allocate Unfrozen Water Content Table **/
      if(options.FROZEN_SOIL) {
	for(i=0;i<MAX_LAYERS;i++) {
	  soil_con.ufwc_table_layer[i] = (double **)malloc((QUICK_FS_TEMPS+1)*sizeof(double *));
	  for(j=0;j<QUICK_FS_TEMPS+1;j++) 
	    soil_con.ufwc_table_layer[i][j] = (double *)malloc(2*sizeof(double));
	}
	for(i=0;i<MAX_NODES;i++) {
	  soil_con.ufwc_table_node[i] = (double **)malloc((QUICK_FS_TEMPS+1)*sizeof(double *));

	  for(j=0;j<QUICK_FS_TEMPS+1;j++) 
	    soil_con.ufwc_table_node[i][j] = (double *)malloc(2*sizeof(double));
	}
      }
#endif /* QUICK_FS */

      NEWCELL=TRUE;
      cellnum++;

#if !OUTPUT_FORCE

      /** Read Grid Cell Vegetation Parameters **/
      veg_con = read_vegparam(filep.vegparam, soil_con.gridcel,
                              Nveg_type);
      calc_root_fractions(veg_con, &soil_con);

      if ( options.LAKES ) 
	lake_con = read_lakeparam(filep.lakeparam, soil_con, veg_con);

#endif // !OUTPUT_FORCE

      /** Build Gridded Filenames, and Open **/
      make_in_and_outfiles(&filep, &filenames, &soil_con, out_data_files);

      if (options.PRT_HEADER) {
        /** Write output file headers **/
        write_header(out_data_files, out_data, dmy, global_param);
      }

#if !OUTPUT_FORCE

      /** Read Elevation Band Data if Used **/
      read_snowband(filep.snowband, &soil_con);

      /** Make Precipitation Distribution Control Structure **/
      prcp     = make_dist_prcp(veg_con[0].vegetat_type_num);

#endif // !OUTPUT_FORCE

      /**************************************************
         Initialize Meteological Forcing Values That
         Have not Been Specifically Set
       **************************************************/

#if VERBOSE
      fprintf(stderr,"Initializing Forcing Data\n");
#endif /* VERBOSE */

      initialize_atmos(atmos, dmy, filep.forcing,
#if OUTPUT_FORCE
		       &soil_con, out_data_files, out_data); 
#else /* OUTPUT_FORCE */
                       &soil_con); 
#endif /* OUTPUT_FORCE */

#if !OUTPUT_FORCE

      /**************************************************
        Initialize Energy Balance and Snow Variables 
      **************************************************/

#if VERBOSE
      fprintf(stderr,"Model State Initialization\n");
#endif /* VERBOSE */
      ErrorFlag = initialize_model_state(&prcp, dmy[0], &global_param, filep, 
			     soil_con.gridcel, veg_con[0].vegetat_type_num,
			     options.Nnode, Ndist, 
			     atmos[0].air_temp[NR],
			     &soil_con, veg_con, lake_con,
			     &init_STILL_STORM, &init_DRY_TIME);
      if ( ErrorFlag == ERROR ) {
	if ( options.CONTINUEONERROR == TRUE ) {
	  // Handle grid cell solution error
	  fprintf(stderr, "ERROR: Grid cell %i failed in record %i so the simulation has not finished.  An incomplete output file has been generated, check your inputs before rerunning the simulation.\n", soil_con.gridcel, rec);
	  break;
	} else {
	  // Else exit program on cell solution error as in previous versions
	  sprintf(ErrStr, "ERROR: Grid cell %i failed in record %i so the simulation has ended. Check your inputs before rerunning the simulation.\n", soil_con.gridcel, rec);
	  vicerror(ErrStr);
	}
      }
      
#if VERBOSE
      fprintf(stderr,"Running Model\n");
#endif /* VERBOSE */

      /** Update Error Handling Structure **/
      Error.filep = filep;
      Error.out_data_files = out_data_files;

      /** Initialize the storage terms in the water and energy balances **/
      /** Sending a negative record number (-global_param.nrecs) to dist_prec() will accomplish this **/
      ErrorFlag = dist_prec(&atmos[0], &prcp, &soil_con, veg_con,
		  &lake_con, dmy, &global_param, &filep, out_data_files,
		  out_data, &save_data, -global_param.nrecs, cellnum,
                  NEWCELL, LASTREC, init_STILL_STORM, init_DRY_TIME);

      /******************************************
	Run Model in Grid Cell for all Time Steps
	******************************************/

      for ( rec = startrec ; rec < global_param.nrecs; rec++ ) {

        if ( rec == global_param.nrecs - 1 ) LASTREC = TRUE;
        else LASTREC = FALSE;

        ErrorFlag = dist_prec(&atmos[rec], &prcp, &soil_con, veg_con,
		  &lake_con, dmy, &global_param, &filep,
		  out_data_files, out_data, &save_data, rec, cellnum,
                  NEWCELL, LASTREC, init_STILL_STORM, init_DRY_TIME);

        if ( ErrorFlag == ERROR ) {
          if ( options.CONTINUEONERROR == TRUE ) {
            // Handle grid cell solution error
            fprintf(stderr, "ERROR: Grid cell %i failed in record %i so the simulation has not finished.  An incomplete output file has been generated, check your inputs before rerunning the simulation.\n", soil_con.gridcel, rec);
            break;
          } else {
	    // Else exit program on cell solution error as in previous versions
            sprintf(ErrStr, "ERROR: Grid cell %i failed in record %i so the simulation has ended. Check your inputs before rerunning the simulation.\n", soil_con.gridcel, rec);
            vicerror(ErrStr);
	  }
        }

        NEWCELL=FALSE;
	for ( veg = 0; veg <= veg_con[0].vegetat_type_num; veg++ )
	  init_DRY_TIME[veg] = -999;

      }	/* End Rec Loop */

#endif /* !OUTPUT_FORCE */

      close_files(&filep,out_data_files,&filenames); 

#if !OUTPUT_FORCE

#if QUICK_FS
      if(options.FROZEN_SOIL) {
	for(i=0;i<MAX_LAYERS;i++) {
	  for(j=0;j<6;j++) 
	    free((char *)soil_con.ufwc_table_layer[i][j]);
	  free((char *)soil_con.ufwc_table_layer[i]);
	}
	for(i=0;i<MAX_NODES;i++) {
	  for(j=0;j<6;j++) 
	    free((char *)soil_con.ufwc_table_node[i][j]);
	  free((char *)soil_con.ufwc_table_node[i]);
	}
      }
#endif /* QUICK_FS */
      free_dist_prcp(&prcp,veg_con[0].vegetat_type_num);
      free_vegcon(&veg_con);
      free((char *)soil_con.AreaFract);
      free((char *)soil_con.BandElev);
      free((char *)soil_con.Tfactor);
      free((char *)soil_con.Pfactor);
      free((char *)soil_con.AboveTreeLine);
      free((char*)init_STILL_STORM);
      free((char*)init_DRY_TIME);
#endif /* !OUTPUT_FORCE */
    }	/* End Run Model Condition */
  } 	/* End Grid Loop */

  /** cleanup **/
  free_atmos(global_param.nrecs, &atmos);
  free_dmy(&dmy);
  free_out_data_files(&out_data_files);
  free_out_data(&out_data);
#if !OUTPUT_FORCE
  free_veglib(&veg_lib);
#endif /* !OUTPUT_FORCE */
  fclose(filep.soilparam);
#if !OUTPUT_FORCE
  fclose(filep.vegparam);
  fclose(filep.veglib);
  if (options.SNOW_BAND>1)
    fclose(filep.snowband);
  if (options.LAKES)
    fclose(filep.lakeparam);
  if ( options.INIT_STATE )
    fclose(filep.init_state);
  if ( options.SAVE_STATE && strcmp( filenames.statefile, "NONE" ) != 0 )
    fclose(filep.statefile);

#endif /* !OUTPUT_FORCE */

  return EXIT_SUCCESS;
}	/* End Main Program */
void alloc_atmos(int nrecs, atmos_data_struct **atmos)
/*******************************************************************
  alloc_atmos

  Modifications:
  01-11-00 Fixed allocation bug                             KAC
  2006-Sep-23 Implemented flexible output configuration; removed
	      LDAS_OUTPUT and OPTIMIZE compile-time options.		TJB
  2006-Dec-20 All atmos_data arrays are always dynamically allocated
	      now.							TJB
  2010-Mar-31 Added runoff_in.						TJB
  2010-Sep-24 Renamed runoff_in to channel_in.				TJB
  2011-Nov-04 Added tskc.						TJB
  2013-Jul-25 Added Catm, coszen, fdir, and par.			TJB

*******************************************************************/
{
    extern param_set_struct param_set;

    int i;

    *atmos = (atmos_data_struct *) calloc(nrecs, sizeof(atmos_data_struct));
    if (*atmos == NULL)
        vicerror("Memory allocation error in alloc_atmos().");

    for (i = 0; i < nrecs; i++) {
        (*atmos)[i].air_temp = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].air_temp == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].Catm = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].Catm == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].channel_in = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].channel_in == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].coszen = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].coszen == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].density = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].density == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].fdir = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].fdir == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].longwave = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].longwave == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].par = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].par == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].prec = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].prec == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].pressure = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].pressure == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].shortwave = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].shortwave == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].snowflag = (char *) calloc(NR+1, sizeof(char));
        if ((*atmos)[i].snowflag == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].tskc = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].tskc == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].vp = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].vp == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].vpd = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].vpd == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].wind = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].wind == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].irr_run = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].irr_run == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
        (*atmos)[i].irr_with = (double *) calloc(NR+1, sizeof(double));
        if ((*atmos)[i].irr_with == NULL)
            vicerror("Memory allocation error in alloc_atmos().");
    }

}
void mtclim42_wrapper(int have_dewpt, int have_shortwave, double hour_offset,
		      double elevation, double annual_prcp, double lat, 
		      global_param_struct *vic_global, dmy_struct *dmy, 
		      double *prec, double *tmax, double *tmin, double *tskc,
		      double *vp, double *hourlyrad) 
{
  control_struct ctrl;
  parameter_struct p;
  data_struct mtclim42_data;
  long ntinys;
  double *tiny_radfract;

  /* allocate space for the tiny_radfract array */
  ntinys = (long) 86400L/(long)SRADDT;
  ntinys *= 366L;
  tiny_radfract = (double *) calloc(ntinys, sizeof(double));
  if (tiny_radfract == NULL) {
    vicerror("Memory allocation error in mtclim42_init() ...\n");
  }

  /* initialize the mtclim 4.2 data structures */ 
  mtclim42_init(have_dewpt, elevation, annual_prcp, lat, vic_global, dmy, prec,
		tmax, tmin, hourlyrad, tiny_radfract, &ctrl, &p,
		&mtclim42_data);  

  /* calculate daily air temperatures */
  if (calc_tair(&ctrl, &p, &mtclim42_data)) {
    vicerror("Error in calc_tair()... exiting\n");
  }
  
  /* calculate daily precipitation */
  if (calc_prcp(&ctrl, &p, &mtclim42_data)) {
    vicerror("Error in calc_prcp()... exiting\n");
  }
  
  /* test for the presence of Tdew observations, and branch to the
     appropriate srad and humidity algorithms */
  if (ctrl.indewpt) {
    /* calculate srad and humidity using real Tdew data */
    if (calc_srad_humidity(&ctrl, &p, &mtclim42_data, tiny_radfract)) {
      vicerror("Error in calc_srad_humidity()... exiting\n");
    }
  }
  else { /* no dewpoint temperature data */
    /* calculate srad and humidity with iterative algorithm */
    if (calc_srad_humidity_iterative(&ctrl, &p, &mtclim42_data,
				     tiny_radfract)) { 
      vicerror("Error in calc_srad_humidity_iterative()... exiting\n");
    }
  }

  /* translate the mtclim 4.2 structures back to the VIC data structures */
  mtclim42_to_vic(have_dewpt, have_shortwave, hour_offset, vic_global,
		  dmy, tiny_radfract, &ctrl,&mtclim42_data, tskc, vp,
		  hourlyrad);

  /* clean up */
  if (data_free(&ctrl, &mtclim42_data)) {
    vicerror("Error in data_free()... exiting\n");
  }  
  free(tiny_radfract);
}
/*****************************************************************************
  Function name: CalcAerodynamic()

  Purpose      : Calculate the aerodynamic resistance for each vegetation 
                 layer, and the wind 2m above the layer boundary.  In case of 
                 an overstory, also calculate the wind in the overstory.
                 The values are normalized based on a reference height wind 
                 speed, Uref, of 1 m/s.  To get wind speeds and aerodynamic 
                 resistances for other values of Uref, you need to multiply 
                 the here calculated wind speeds by Uref and divide the 
                 here calculated aerodynamic resistances by Uref
                 
  Required     :
    int NVegLayers - Number of vegetation layers
    char OverStory - flag for presence of overstory.  Only used if NVegLayers 
                     is equal to 1
    double Zref[0]     - Reference height for windspeed
    double n        - Attenuation coefficient for wind in the overstory
    double Height  - Height of the vegetation layers (top layer first)
    double Trunk    - Multiplier for Height[0] that indictaes the top of the 
                     trunk space
    double *U       - Vector of length 2, with wind for vegetation layers
                     If OverStory == TRUE the first value is the wind in
                     VIC vegetation, and the second value the wind 
                     in the overstory.  Otherwise the first 
                     value is the wind in the VIC vegetation and 
                     the second value is not used.
                     The third value is aerodynamic resistance over snow.
    double *Ra      - Vector of length 3, with aerodynamic resistance values.  
                     If OverStory == TRUE the first value is the aerodynamic 
                     resistance for VIC vegetation, and the second 
                     value the aerodynamic resistance for the overstory (for
		     use in the snow interception routine).  
                     Otherwise the first value is the aerodynamic resistance
                     for VIC vegetation and the second value is not used.
                     The third value is aerodynamic resistance over snow.

  Returns      : void

  Modifies     :
    double *U
    double *Ra     
   
  Comments     :
*****************************************************************************/
void CalcAerodynamic(char   OverStory, 
                     int    iveg,
                     int    Nveg,
                     double n,
                     double Height,
		     double Z0_SOIL,
		     double Z0_SNOW,
                     double *displacement,
                     double *roughness,
                     double *Zref,
                     double Trunk,
                     double *U, 
                     double *Ra) 
{
  double d_Lower;
  double d_Upper;
  double K2;
  double Uh;
  double Ut;
  double Uw;
  double Z0_Lower;
  double Z0_Upper;
  double Zt;
  double Zw;
  double tmp_wind;

  tmp_wind = U[0];

  K2 = von_K * von_K;
  
  /* No OverStory, thus maximum one soil layer */
  
  if (OverStory == FALSE) {
    
    if (iveg == Nveg) {
      Z0_Lower = Z0_SOIL;
      d_Lower  = 0; 
    }
    else {
      Z0_Lower = *roughness;
      d_Lower  = *displacement;
    }
    
    /* No snow */
    U[0]  = log((2. + Z0_Lower)/Z0_Lower)/log((Zref[0] - d_Lower)/Z0_Lower);
    /****** DHSVM ******
    Ra[0] = log((2. + Z0_Lower)/Z0_Lower) * log((Zref[0] - d_Lower)/Z0_Lower)
            /K2;
    ***** Old VIC *****/
    Ra[0] = log((2. + (1.0/0.63 - 1.0) * d_Lower) / Z0_Lower)
          * log((2. + (1.0/0.63 - 1.0) * d_Lower) / (0.1*Z0_Lower)) / K2;
    /******************/

    /* Snow */
    U[2] = log((2. + Z0_SNOW)/Z0_SNOW)/log(Zref[0]/Z0_SNOW);
    Ra[2] = log((2. + Z0_SNOW)/Z0_SNOW) * log(Zref[0]/Z0_SNOW)/K2;
  }
  
  /* Overstory present, one or two vegetation layers possible */
  else {
    Z0_Upper = *roughness;
    d_Upper  = *displacement;
    
    Z0_Lower = Z0_SOIL;
    d_Lower  = 0; 
    
    Zw = 1.5 * Height - 0.5 * d_Upper;
    Zt = Trunk * Height;
    if (Zt < (Z0_Lower+d_Lower)) 
      vicerror("ERROR: Trunk space height below \"center\" of lower boundary");

    /* Resistance for overstory */
    Ra[1] = log((Zref[0]-d_Upper)/Z0_Upper)/K2
          * (Height/(n*(Zw-d_Upper)) 
          * (exp(n*(1-(d_Upper+Z0_Upper)/Height))-1)
          + (Zw-Height)/(Zw-d_Upper)
          + log((Zref[0]-d_Upper)/(Zw-d_Upper)));
    
    /* Wind at different levels in the profile */
    Uw = log((Zw-d_Upper)/Z0_Upper) / log((Zref[0]-d_Upper)/Z0_Upper);
    Uh = Uw - (1-(Height-d_Upper)/(Zw-d_Upper))
       / log((Zref[0]-d_Upper)/Z0_Upper);
    U[1] = Uh * exp(n * ((Z0_Upper+d_Upper)/Height - 1.));
    Ut = Uh * exp(n * (Zt/Height - 1.));
    
    /* resistance at the lower boundary */
    

    /***** Old VIC *****/
    U[0]  = log((2. + Z0_Upper)/Z0_Upper)/log((Zref[0] - d_Upper)/Z0_Upper);
    Ra[0] = log((2. + (1.0/0.63 - 1.0) * d_Upper) / Z0_Upper)
          * log((2. + (1.0/0.63 - 1.0) * d_Upper) / (0.1*Z0_Upper)) / K2;
    /******************/



    /* Snow */
    /* case 1: the wind profile to a height of 2m above the lower boundary is 
       entirely logarithmic */
    if (Zt > (2. + Z0_SNOW)) {
      U[2] = Ut*log((2.+Z0_SNOW)/Z0_SNOW)/log(Zt/Z0_SNOW);
      Ra[2] = log((2.+Z0_SNOW)/Z0_SNOW) * log(Zt/Z0_SNOW)/(K2*Ut);  
    }
    
    /* case 2: the wind profile to a height of 2m above the lower boundary 
       is part logarithmic and part exponential, but the top of the overstory 
       is more than 2 m above the lower boundary */
    else if (Height > (2. + Z0_SNOW)) {
      U[2] = Uh * exp(n * ((2. + Z0_SNOW)/Height - 1.));
      Ra[2] = log(Zt/Z0_SNOW) * log(Zt/Z0_SNOW)/
        (K2*Ut) +
        Height * log((Zref[0]-d_Upper)/Z0_Upper) / (n*K2*(Zw-d_Upper)) *
        (exp(n*(1-Zt/Height)) - exp(n*(1-(Z0_SNOW+2.)/Height)));
    }
    
    /* case 3: the top of the overstory is less than 2 m above the lower 
       boundary.  The wind profile above the lower boundary is part 
       logarithmic and part exponential, but only extends to the top of the 
       overstory */
    else {
      U[2] = Uh;
      Ra[2] = log(Zt/Z0_SNOW) * log(Zt/Z0_SNOW)/
        (K2*Ut) +
        Height * log((Zref[0]-d_Upper)/Z0_Upper) / (n*K2*(Zw-d_Upper)) *
        (exp(n*(1-Zt/Height)) - 1);
      fprintf(stderr, "WARNING:  Top of overstory is less than 2 meters above the lower boundary\n");
    }
  }

  if(tmp_wind>0.) {
    U[0] *= tmp_wind;
    Ra[0] /= tmp_wind;
    if(U[1]!=-999) {
      U[1] *= tmp_wind;
      Ra[1] /= tmp_wind;
    }
    if(U[2]!=-999) {
      U[2] *= tmp_wind;
      Ra[2] /= tmp_wind;
    }
  }
  else {
    U[0] *= tmp_wind;
    Ra[0] = HUGE_RESIST;
    if(U[1]!=-999)
      U[1] *= tmp_wind;
    Ra[1] = HUGE_RESIST;
    if(U[2]!=-999)
      U[2] *= tmp_wind;
    Ra[2] = HUGE_RESIST;
  }
}
void mtclim42_init(int have_dewpt, double elevation, double annual_prcp, 
		   double lat, global_param_struct *vic_global, dmy_struct *dmy, 
		   double *prec, double *tmax, double *tmin, double *hourlyrad, 
		   double *tiny_radfract, control_struct *ctrl, 
		   parameter_struct *p, data_struct *mtclim42_data)
{
  int i;
  int stepspday;
  long tinystepspyear;

  /* initialize the control structure */

  ctrl->ndays = (vic_global->nrecs*vic_global->dt)/24;
  
  if (have_dewpt)
    vicerror("have_dewpt not yet implemented...\n");
  else
    ctrl->indewpt = 0;
  ctrl->outhum = 1;		/* output vapor pressure */
  ctrl->inyear = 0;
  
  /* initialize the parameter structure.  Meteorological variables are only
     calculated for the mean grid cell elevation.  The temperatures are lapsed
     outside of the mtclim code.  Therefore p->base_elev and p->site_elev are
     set to the same value.  The same is true for p->base_isoh and
     p->site_isoh. */
  p->base_elev   = elevation;
  p->base_isoh   = annual_prcp/10.; /* MTCLIM prcp in cm */
  p->site_lat    = lat;
  p->site_elev   = elevation;
  p->site_slp    = 0.;
  p->site_asp    = 0.;
  p->site_isoh   = annual_prcp/10.; /* MTCLIM prcp in cm */
  p->site_ehoriz = 0.;
  p->site_whoriz = 0.;
  p->tmax_lr     = T_lapse;	    /* not used since site_elev == base_elev */
  p->tmin_lr     = T_lapse;	    /* not used since site_elev == base_elev */

  /* allocate space in the data arrays for input and output data */
  if (data_alloc(ctrl, mtclim42_data)) {
    vicerror("Error in data_alloc()... exiting\n");
  }

  /* First populate the solar day array with the tmin, tmax, prcp and possibly
     the Tdew values for the corresponding local days.  At
     this point we will not worry about the first and last incomplete solar days 
     (if there are any).  It could be argued that the mtclim method does not
     make all that much sense if you only have data for one or two days
     anyway. */

  /* in this first version we just take care of the daily data, subdaily data
     will be implemented later */
     
  /* initialize the data arrays with the vic input data */
  stepspday = 24/vic_global->dt;
  for (i = 0; i < ctrl->ndays; i++) {
    mtclim42_data->yday[i] = dmy[i*stepspday].day_in_year;
    mtclim42_data->tmax[i] = tmax[i];
    mtclim42_data->tmin[i] = tmin[i];
    /* MTCLIM prcp in cm */
    mtclim42_data->prcp[i] = prec[i]/10.; 
    if (have_dewpt)
      vicerror("have_dewpt not yet implemented ...\n");
  }
  tinystepspyear = 366L*(86400L/(long)SRADDT);
  for (i = 0; i < tinystepspyear; i++)
    tiny_radfract[i] = 0;
}