/*
 * SUMMARY:      InitConstants.c - Initialize constants for DHSVM
 * USAGE:        Part of DHSVM
 *
 * AUTHOR:       Bart Nijssen
 * ORG:          University of Washington, Department of Civil Engineering
 * E-MAIL:       nijssen@u.washington.edu
 * ORIG-DATE:    Apr-96 
 * Last Change: Mon Nov  4 16:26:37 2002 by Scott Waichler <waichler@tuff.pnl.gov>
 * DESCRIPTION:  Initialize constants for DHSVM
 * DESCRIP-END.
 * FUNCTIONS:    InitConstants()
 * COMMENTS:     
 */

#ifndef lint
static char vcid[] = "$Id: InitConstants.c,v 1.2 2001/03/31 00:10:25 waichler Exp $";
#endif /* lint */

#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "settings.h"
#include "data.h"
#include "Calendar.h"
#include "fileio.h"
#include "DHSVMerror.h"
#include "functions.h"
#include "getinit.h"
#include "constants.h"
#include "init.h"
#include "rad.h"
#include "round.h"
#include "calcsolar.h"
#include "inittime.h"

/*****************************************************************************
  Function name: InitConstants()

  Purpose      : Initialize constants and settings for DHSVM run
                 Processes the following sections in InFile:
                 [OPTIONS]
                 [AREA]
                 [TIME]
                 [CONSTANTS}

  Required     :
    LISTPTR Input          - Linked list with input strings
    OPTIONSTRUCT *Options   - Structure with different program options
    MAPSIZE *Map            - Coverage and resolution of model area
    SOLARGEOMETRY *SolarGeo - Solar geometry information
    TIMESTRUCT *Time        - Begin and end times, model timestep

  Returns      : void

  Modifies     : (see list of required above)

  Comments     :
*****************************************************************************/
void InitConstants(LISTPTR Input, OPTIONSTRUCT *Options, MAPSIZE *Map, 
                   SOLARGEOMETRY *SolarGeo, TIMESTRUCT *Time)
{
  int i;                        /* counter */
  double PointModelX;           /* X-coordinate for POINT model mode */
  double PointModelY;           /* Y-coordinate for POINT model mode */
  float TimeStep;		/* Timestep in hours */
  DATE End;			/* End of run */
  DATE Start;			/* Start of run */

  STRINIENTRY StrEnv[] = {
    {"OPTIONS", "FORMAT"                    , ""  , ""},
    {"OPTIONS", "EXTENT"                    , ""  , ""},
    {"OPTIONS", "GRADIENT"                  , ""  , ""},
    {"OPTIONS", "READ FLOW DIRECTIONS"      , ""  , ""},
    {"OPTIONS", "FLOW ROUTING"              , ""  , ""},
    {"OPTIONS", "SENSIBLE HEAT FLUX"        , ""  , ""},
    {"OPTIONS", "INTERPOLATION"             , ""  , ""},
    {"OPTIONS", "MM5"                       , ""  , ""},
    {"OPTIONS", "QPF"                       , ""  , ""},
    {"OPTIONS", "PRISM"                     , ""  , ""},
    {"OPTIONS", "SNOTEL"                    , ""  , ""},
    {"OPTIONS", "OUTSIDE"                   , ""  , ""},
    {"OPTIONS", "RHOVERRIDE"                , ""  , ""},
    {"OPTIONS", "RADIATION"                 , ""  , ""},
    {"OPTIONS", "PRECIPITATION SOURCE"      , ""  , ""},
    {"OPTIONS", "WIND SOURCE"               , ""  , ""},
    {"OPTIONS", "TEMPERATURE LAPSE RATE"    , ""  , ""},
    {"OPTIONS", "PRECIPITATION LAPSE RATE"  , ""  , ""},  
    {"OPTIONS", "CRESSMAN RADIUS"           , ""  , ""},
    {"OPTIONS", "CRESSMAN STATIONS"         , ""  , ""},
    {"OPTIONS", "INFILTRATION"              , ""  , ""},
    {"OPTIONS", "HYDRAULIC ROUTING"         , ""  , ""},
    {"OPTIONS", "CHANNEL ROUTING"           , ""  , ""},
    {"OPTIONS", "GROUNDWATER"               , ""  , ""},
    {"OPTIONS", "FROZEN SOIL"               , ""  , ""},
    {"AREA"   , "COORDINATE SYSTEM"         , ""  , ""},
    {"AREA"   , "EXTREME NORTH"             , ""  , ""},
    {"AREA"   , "EXTREME WEST"              , ""  , ""},
    {"AREA"   , "CENTER LATITUDE"           , ""  , ""},
    {"AREA"   , "CENTER LONGITUDE"          , ""  , ""},
    {"AREA"   , "TIME ZONE MERIDIAN"        , ""  , ""},
    {"AREA"   , "NUMBER OF ROWS"            , ""  , ""},
    {"AREA"   , "NUMBER OF COLUMNS"         , ""  , ""},
    {"AREA"   , "GRID SPACING"              , ""  , ""},
    {"AREA"   , "POINT NORTH"               , ""  , ""},
    {"AREA"   , "POINT EAST"                , ""  , ""},
    {"TIME"   , "TIME STEP"                 , ""  , ""},
    {"TIME"   , "MODEL START"               , ""  , ""},
    {"TIME"   , "MODEL END"                 , ""  , ""},
    {"CONSTANTS", "GROUND ROUGHNESS"        , ""  , ""},
    {"CONSTANTS", "SNOW ROUGHNESS"          , ""  , ""},
    {"CONSTANTS", "RAIN THRESHOLD"          , ""  , ""},
    {"CONSTANTS", "SNOW THRESHOLD"          , ""  , ""},
    {"CONSTANTS", "SNOW WATER CAPACITY"     , ""  , ""},
    {"CONSTANTS", "REFERENCE HEIGHT"        , ""  , ""},
    {"CONSTANTS", "RAIN LAI MULTIPLIER"     , ""  , ""},
    {"CONSTANTS", "SNOW LAI MULTIPLIER"     , ""  , ""},
    {"CONSTANTS", "MIN INTERCEPTED SNOW"    , ""  , ""},
    {"CONSTANTS", "OUTSIDE BASIN VALUE"     , ""  , ""},
    {"CONSTANTS", "TEMPERATURE LAPSE RATE"  , ""  , ""},
    {"CONSTANTS", "PRECIPITATION LAPSE RATE", ""  , ""},
    {NULL       , NULL                      , ""  , NULL}
  };


  /* Read the key-entry pairs from the input file */
  for (i = 0; StrEnv[i].SectionName; i++)
    GetInitString(StrEnv[i].SectionName, StrEnv[i].KeyName, StrEnv[i].Default,
                  StrEnv[i].VarStr, (unsigned long) BUFSIZE, Input);


  /**************** Determine model options ****************/
  
  /* Determine file format to be used */
  if (strncmp(StrEnv[format].VarStr, "BIN", 3) == 0) 
    Options->FileFormat = BIN;
  else if (strncmp(StrEnv[format].VarStr, "NETCDF", 3) == 0)
    Options->FileFormat = NETCDF;
  else
    ReportError(StrEnv[format].KeyName, 51);

  /* Determine whether the model should be run in POINT mode, BASIN mode,
     or ELEVBAND mode.
     If in POINT mode also read which pixel to model */
  if (strncmp(StrEnv[extent].VarStr, "POINT", 5) == 0) {
    Options->Extent = POINT;
    Options->HasNetwork = FALSE;
  }
  else if (strncmp(StrEnv[extent].VarStr, "BASIN", 5) == 0) {
    Options->Extent = BASIN;
  }
  else if (strncmp(StrEnv[extent].VarStr, "ELEVBAND", 8) == 0) {
    Options->Extent = ELEVBAND;
  }
  else
    ReportError(StrEnv[extent].KeyName, 51);

  /* Determine how the flow gradient should be calculated */
  if (Options->Extent != POINT) {
    if (strncmp(StrEnv[gradient].VarStr, "TOPO", 4) == 0)
      Options->FlowGradient = TOPOGRAPHY;
    else if (strncmp(StrEnv[gradient].VarStr, "WATER", 5) == 0)
      Options->FlowGradient = WATERTABLE;
    else
      ReportError(StrEnv[gradient].KeyName, 51);
  }
  else
    Options->FlowGradient = NOT_APPLICABLE;

  /* Determine how to obtain flow directions */
  if (strncmp(StrEnv[read_flowdir].VarStr, "TRUE", 4) == 0) {
    Options->ReadFlowDir = TRUE;
    i = NDIRS;
    if( i == 4 ) {
      fprintf( stderr, "ERROR: Reading Flow Directions: NDIR must equal 8\n");
      exit(1);
    }
    if( Options->FlowGradient == WATERTABLE ) {
      printf("Reading flow directions: FlowGradient changed from WATERTABLE to TOPOGRAPHY\n" );
      Options->FlowGradient = TOPOGRAPHY;
    }
  }
  else if (strncmp(StrEnv[read_flowdir].VarStr, "FALSE", 5) == 0)
    Options->ReadFlowDir = FALSE;
  else
    ReportError(StrEnv[read_flowdir].KeyName, 51);

  /* Determine what meterological interpolation to use */

    if (strncmp(StrEnv[interpolation].VarStr, "INVDIST", 7) == 0)
      Options->Interpolation = INVDIST;
    else if (strncmp(StrEnv[interpolation].VarStr, "NEAREST", 7) == 0)
      Options->Interpolation = NEAREST;
    else if  (strncmp(StrEnv[interpolation].VarStr, "VARCRESS", 8) == 0)
      Options->Interpolation = VARCRESS;
    else if  (strncmp(StrEnv[interpolation].VarStr, "READ", 8) == 0)
      Options->Interpolation = READ;
    else
      ReportError(StrEnv[interpolation].KeyName, 51);

    /* if VARIABLE CRESTMAN interpolation then get parameters */
    if (Options->Interpolation == VARCRESS) {
      if (!CopyInt(&(Options->CressRadius), StrEnv[cressman_radius].VarStr, 1))
        ReportError(StrEnv[cressman_radius].KeyName, 51);
    if  (!CopyInt(&(Options->CressStations), StrEnv[cressman_stations].VarStr, 1))
      ReportError(StrEnv[cressman_stations].KeyName, 51);  
    } 

  /* Determine whether a road/network is imposed on the model area */
  if (Options->Extent != POINT) {
    if (strncmp(StrEnv[flow_routing].VarStr, "NETWORK", 7) == 0) 
    Options->HasNetwork = TRUE;
    else if (strncmp(StrEnv[flow_routing].VarStr, "UNIT", 4) == 0)
      Options->HasNetwork = FALSE;
    else
      ReportError(StrEnv[flow_routing].KeyName, 51);
  }
  else
    Options->HasNetwork = FALSE;

  /* Determine whether a sensible heat flux should be calculated */
  if (strncmp(StrEnv[sensible_heat_flux].VarStr, "TRUE", 4) == 0)
    Options->HeatFlux = TRUE;
  else if (strncmp(StrEnv[sensible_heat_flux].VarStr, "FALSE", 5) == 0)
    Options->HeatFlux = FALSE;
  else
    ReportError(StrEnv[sensible_heat_flux].KeyName, 51);


  /* Determine whether the mm5 interface should be used */
  if (strncmp(StrEnv[mm5].VarStr, "TRUE", 4) == 0)
    Options->MM5 = TRUE;
  else if (strncmp(StrEnv[mm5].VarStr, "FALSE", 5) == 0)
    Options->MM5 = FALSE;
  else
    ReportError(StrEnv[mm5].KeyName, 51);

  /* Determine whether the QPF override should be used on the MM5 fields*/
  if (strncmp(StrEnv[qpf].VarStr, "TRUE", 4) == 0)
    Options->QPF = TRUE;
  else if (strncmp(StrEnv[qpf].VarStr, "FALSE", 5) == 0)
    Options->QPF = FALSE;
  else
    ReportError(StrEnv[qpf].KeyName, 51);

    /* Determine if PRISM maps will be used to interpolate precip fields*/
    if (strncmp(StrEnv[prism].VarStr, "TRUE", 4) == 0) 
      Options->Prism = TRUE;
    else if (strncmp(StrEnv[prism].VarStr, "FALSE", 5) == 0)
      Options->Prism = FALSE;
    else
      ReportError(StrEnv[prism].KeyName, 51);

    /* Determine if Snotel test is called for*/
    if (strncmp(StrEnv[snotel].VarStr, "TRUE", 4) == 0) 
      Options->Snotel = TRUE;
    else if (strncmp(StrEnv[snotel].VarStr, "FALSE", 5) == 0)
      Options->Snotel = FALSE;
    else
      ReportError(StrEnv[snotel].KeyName, 51);

    /* Determine if listed met stations outside bounding box are used*/
    if (strncmp(StrEnv[outside].VarStr, "TRUE", 4) == 0) 
      Options->Outside = TRUE;
    else if (strncmp(StrEnv[outside].VarStr, "FALSE", 5) == 0)
      Options->Outside = FALSE;
    else
      ReportError(StrEnv[outside].KeyName, 51);

    /* Determine if rh override is used*/
    if (strncmp(StrEnv[rhoverride].VarStr, "TRUE", 4) == 0) 
      Options->Rhoverride= TRUE;
    else if (strncmp(StrEnv[rhoverride].VarStr, "FALSE", 5) == 0)
      Options->Rhoverride = FALSE;
    else
      ReportError(StrEnv[rhoverride].KeyName, 51);

  /* The other met options are only of importance if MM5 is FALSE */

  if (Options->MM5 == TRUE) {
    Options->RadType     = NOT_APPLICABLE;
    Options->PrecipType  = NOT_APPLICABLE;
    Options->WindSource  = NOT_APPLICABLE;
    Options->PrecipLapse = NOT_APPLICABLE;
    Options->TempLapse   = NOT_APPLICABLE;
    if(Options->QPF == TRUE) Options->PrecipType=STATION;
  }
  else {
    /* Determine type of radiation calculation to be used, i.e. either IPW or
       INLINE */
    if (strncmp(StrEnv[radiation].VarStr, "IPW", 3) == 0) 
      Options->RadType = IPW;
    else if (strncmp(StrEnv[radiation].VarStr, "INLINE", 6) == 0)
      Options->RadType = INLINE;
    else
      ReportError(StrEnv[radiation].KeyName, 51);

    /* Determine the type of precipitation data that the model will use */
    if (strncmp(StrEnv[precipitation_source].VarStr, "RADAR", 5) == 0) 
      Options->PrecipType = RADAR;
    else if (strncmp(StrEnv[precipitation_source].VarStr, "STATION", 7) == 0)
      Options->PrecipType = STATION;
    else
      ReportError(StrEnv[precipitation_source].KeyName, 51);

    /* Determine the type of wind data that the model will use */
    if (strncmp(StrEnv[wind_source].VarStr, "MODEL", 5) == 0) 
      Options->WindSource = MODEL;
    else if (strncmp(StrEnv[wind_source].VarStr, "STATION", 7) == 0)
      Options->WindSource = STATION;
    else
      ReportError(StrEnv[wind_source].KeyName, 51);

    /* Determine the type of temperature lapse rate */
    if (strncmp(StrEnv[temp_lapse].VarStr, "CONSTANT", 8) == 0) 
      Options->TempLapse = CONSTANT;
    else if (strncmp(StrEnv[temp_lapse].VarStr, "VARIABLE", 8) == 0)
      Options->TempLapse = VARIABLE;
    else
      ReportError(StrEnv[temp_lapse].KeyName, 51);

    /* Determine the type of precipitation lapse rate */
    if (strncmp(StrEnv[precip_lapse].VarStr, "CONSTANT", 8) == 0) 
      Options->PrecipLapse = CONSTANT;
    else if (strncmp(StrEnv[precip_lapse].VarStr, "MAP", 3) == 0) 
      Options->PrecipLapse = MAP;
    else if (strncmp(StrEnv[precip_lapse].VarStr, "VARIABLE", 8) == 0)
      Options->PrecipLapse = VARIABLE;

    /* Added by SRW 08/14/02 for the Hanford recharge project 
       See LapseT.c for usage.  */
    else if (strncmp(StrEnv[precip_lapse].VarStr, "HANFORD", 7) == 0)
      Options->PrecipLapse = HANFORD;

    else
      ReportError(StrEnv[precip_lapse].KeyName, 51);

    /* Determine the type of infiltration rate */
    if (strncmp(StrEnv[infiltration].VarStr, "CONSTANT", 8) == 0) 
      Options->Infiltration = CONSTANT;
    else if (strncmp(StrEnv[infiltration].VarStr, "VARIABLE", 8) == 0)
      Options->Infiltration = VARIABLE;
    else
      ReportError(StrEnv[infiltration].KeyName, 51);

    /* Determine type of overland flow routing.  Does it matter
       if there is a stream network or not?  SRW 11/04/02.  */
    if( Options->HasNetwork == TRUE ) {
      if (strncmp(StrEnv[hydraulic_routing].VarStr, "LINEAR", 6) == 0) 
        Options->HydraulicRouting = LINEAR;
      else if (strncmp(StrEnv[hydraulic_routing].VarStr, "POWERLAW", 8) == 0)
        Options->HydraulicRouting = POWERLAW;
      else if (strncmp(StrEnv[hydraulic_routing].VarStr, "FTABLE", 6) == 0)
        Options->HydraulicRouting = FTABLE;
      else if (strncmp(StrEnv[hydraulic_routing].VarStr, "CASCADE_LINEAR", 14) == 0)
        Options->HydraulicRouting = CASCADE_LINEAR;
      else if (strncmp(StrEnv[hydraulic_routing].VarStr, "CASCADE_LINEAR_LIMITED", 22) == 0)
        Options->HydraulicRouting = CASCADE_LINEAR_LIMITED;
      else if (strncmp(StrEnv[hydraulic_routing].VarStr, "CASCADE_POWERLAW", 16) == 0)
        Options->HydraulicRouting = CASCADE_POWERLAW;
      else
        ReportError(StrEnv[hydraulic_routing].KeyName, 51);
    }
    else 
      Options->HydraulicRouting = NOT_APPLICABLE;
    printf("HydraulicRouting =%d \n", Options->HydraulicRouting);

    /* Determine type of channel flow routing.  */
    if( Options->HasNetwork == TRUE ) {
      if (strncmp(StrEnv[channel_routing].VarStr, "LINEAR", 6) == 0) 
        Options->ChannelRouting = LINEAR;
      else if (strncmp(StrEnv[channel_routing].VarStr, "POWERLAW", 8) == 0)
        Options->ChannelRouting = POWERLAW;
      else if (strncmp(StrEnv[channel_routing].VarStr, "FTABLE", 6) == 0)
        Options->ChannelRouting = FTABLE;
      else
        ReportError(StrEnv[channel_routing].KeyName, 51);
    }
    else 
      Options->ChannelRouting = NOT_APPLICABLE;
    printf("ChannelRouting =%d \n", Options->ChannelRouting);

    /* determine if deeper groundwater is represented */
      if (strncmp(StrEnv[groundwater].VarStr, "TRUE", 4) == 0) 
        Options->Groundwater = TRUE;
      else if (strncmp(StrEnv[groundwater].VarStr, "FALSE", 5) == 0)
        Options->Groundwater = FALSE;
      else
        ReportError(StrEnv[groundwater].KeyName, 51);

    /* determine if frozen soils are simulated */
      if (strncmp(StrEnv[frozensoil].VarStr, "TRUE", 4) == 0) 
        Options->FrozenSoil = TRUE;
      else if (strncmp(StrEnv[frozensoil].VarStr, "FALSE", 5) == 0)
        Options->FrozenSoil = FALSE;
      else
        ReportError(StrEnv[frozensoil].KeyName, 51);


  }

  /**************** Determine areal extent ****************/

  if (IsEmptyStr(StrEnv[coordinate_system].VarStr))
    ReportError(StrEnv[coordinate_system].KeyName, 51);
  strcpy(Map->System, StrEnv[coordinate_system].VarStr);

  if (!CopyDouble(&(Map->Yorig), StrEnv[extreme_north].VarStr, 1))
    ReportError(StrEnv[extreme_north].KeyName, 51);

  if (!CopyDouble(&(Map->Xorig), StrEnv[extreme_west].VarStr, 1))
    ReportError(StrEnv[extreme_west].KeyName, 51);
    
  if (!CopyFloat(&(SolarGeo->Latitude), StrEnv[center_latitude].VarStr, 1))
    ReportError(StrEnv[center_latitude].KeyName, 51);
  SolarGeo->Latitude *= (float) RADPDEG;

  if (!CopyFloat(&(SolarGeo->Longitude), StrEnv[center_longitude].VarStr, 1))
    ReportError(StrEnv[center_longitude].KeyName, 51);
  SolarGeo->Longitude *= (float) RADPDEG;

  if (!CopyFloat(&(SolarGeo->StandardMeridian), 
		  StrEnv[time_zone_meridian].VarStr, 1))
    ReportError(StrEnv[time_zone_meridian].KeyName, 51);
  SolarGeo->StandardMeridian *= (float) RADPDEG;
  
  /* initialize remainder of solar information */
  SolarGeo->SolarAzimuth = 0.0;
  SolarGeo->NoonHour = 0.0;
  SolarGeo->Declination = 0.0;
  SolarGeo->HalfDayLength = 0.0;
  SolarGeo->Sunrise = 0.0;
  SolarGeo->Sunset = 0.0;
  SolarGeo->TimeAdjustment = 0.0;
  SolarGeo->SunEarthDistance = 0.0;
  SolarGeo->SineSolarAltitude = 0.0;
  SolarGeo->DayLight = 0;
  SolarGeo->SolarTimeStep = 0.0;
  SolarGeo->SunMax = 0.0;


  if (!CopyInt(&(Map->NY), StrEnv[number_of_rows].VarStr, 1))
    ReportError(StrEnv[number_of_rows].KeyName, 51);

  if (!CopyInt(&(Map->NX), StrEnv[number_of_columns].VarStr, 1))
    ReportError(StrEnv[number_of_columns].KeyName, 51);

  if (!CopyFloat(&(Map->DY), StrEnv[grid_spacing].VarStr, 1))
    ReportError(StrEnv[grid_spacing].KeyName, 51);

  Map->DX = Map->DY;
  Map->DXY = (float) sqrt(Map->DX * Map->DX + Map->DY * Map->DY);
  Map->X = 0;
  Map->Y = 0;
  Map->OffsetX = 0;
  Map->OffsetY = 0;

  /* set for quick lookup */
#if NDIRS == 4
  Map->xneighbor[0] = 0;     
  Map->yneighbor[0] = -1;    /* N (0 rads) */

  Map->xneighbor[1] = 1;
  Map->yneighbor[1] = 0;     /* E (PI/2 rads)*/

  Map->xneighbor[2] = 0;
  Map->yneighbor[2] = 1;     /* S (PI rads)*/

  Map->xneighbor[3] = -1;
  Map->yneighbor[3] = 0;     /* W (3PI/2 rads or -PI/2 rads)*/
#elif NDIRS == 8
  Map->xneighbor[0] = -1;  /*--------------------------*/
  Map->yneighbor[0] = 1;     /* SW */

  Map->xneighbor[1] = 0;
  Map->yneighbor[1] = 1;     /* S */

  Map->xneighbor[2] = 1;
  Map->yneighbor[2] = 1;     /* SE */

  Map->xneighbor[3] = 1;
  Map->yneighbor[3] = 0;     /* E  */

  Map->xneighbor[4] = 1;
  Map->yneighbor[4] = -1;    /* NE */

  Map->xneighbor[5] = 0;
  Map->yneighbor[5] = -1;    /* N */

  Map->xneighbor[6] = -1;
  Map->yneighbor[6] = -1;    /* NW */

  Map->xneighbor[7] = -1;
  Map->yneighbor[7] = 0;     /* W */
#endif
  
 
  if (Options->Extent == POINT) {

    if (!CopyDouble(&PointModelY, StrEnv[point_north].VarStr, 1))
      ReportError(StrEnv[point_north].KeyName, 51);

    if (!CopyDouble(&PointModelX, StrEnv[point_east].VarStr, 1))
      ReportError(StrEnv[point_east].KeyName, 51);

    Options->PointY = 
      Round(((Map->Yorig - 0.5 * Map->DY) - PointModelY)/Map->DY);
    Options->PointX = 
      Round((PointModelX - (Map->Xorig + 0.5 * Map->DX))/Map->DX);
  } 
  else {
    Options->PointY = 0;
    Options->PointX = 0;
  }
  
  /**************** Determine model period ****************/

  if (!CopyFloat(&(TimeStep), StrEnv[time_step].VarStr, 1))
    ReportError(StrEnv[time_step].KeyName, 51);
  TimeStep *= SECPHOUR;

  if (!SScanDate(StrEnv[model_start].VarStr, &(Start)))
    ReportError(StrEnv[model_start].KeyName, 51);

  if (!SScanDate(StrEnv[model_end].VarStr, &(End)))
    ReportError(StrEnv[model_end].KeyName, 51);
  
  InitTime(Time, &Start, &End, NULL, NULL, (int) TimeStep);

  /**************** Determine model constants ****************/

  if (!CopyFloat(&Z0_GROUND, StrEnv[ground_roughness].VarStr, 1))
    ReportError(StrEnv[ground_roughness].KeyName, 51);

  if (!CopyFloat(&Z0_SNOW, StrEnv[snow_roughness].VarStr, 1))
    ReportError(StrEnv[snow_roughness].KeyName, 51);

  if (!CopyFloat(&MIN_RAIN_TEMP, StrEnv[rain_threshold].VarStr, 1))
    ReportError(StrEnv[rain_threshold].KeyName, 51);

  if (!CopyFloat(&MAX_SNOW_TEMP, StrEnv[snow_threshold].VarStr, 1))
    ReportError(StrEnv[snow_threshold].KeyName, 51);

  if (!CopyFloat(&LIQUID_WATER_CAPACITY, 
		 StrEnv[snow_water_capacity].VarStr, 1))
    ReportError(StrEnv[snow_water_capacity].KeyName, 51);

  if (!CopyFloat(&Zref, StrEnv[reference_height].VarStr, 1))
    ReportError(StrEnv[reference_height].KeyName, 51);

  if (!CopyFloat(&LAI_WATER_MULTIPLIER, 
		  StrEnv[rain_lai_multiplier].VarStr, 1))
    ReportError(StrEnv[rain_lai_multiplier].KeyName, 51);

  if (!CopyFloat(&LAI_SNOW_MULTIPLIER, 
		  StrEnv[snow_lai_multiplier].VarStr, 1))
    ReportError(StrEnv[snow_lai_multiplier].KeyName, 51);

  if (!CopyFloat(&MIN_INTERCEPTION_STORAGE, 
                  StrEnv[min_intercepted_snow].VarStr, 1))
    ReportError(StrEnv[min_intercepted_snow].KeyName, 51);

  if (!CopyUChar(&OUTSIDEBASIN, StrEnv[outside_basin].VarStr, 1))
    ReportError(StrEnv[outside_basin].KeyName, 51);

  if (Options->TempLapse == CONSTANT) {
    if (!CopyFloat(&TEMPLAPSE, StrEnv[temp_lapse_rate].VarStr, 1))
      ReportError(StrEnv[temp_lapse_rate].KeyName, 51);
  }
  else
    TEMPLAPSE = NOT_APPLICABLE;

  if (Options->PrecipLapse == CONSTANT) {
    if (!CopyFloat(&PRECIPLAPSE, StrEnv[precip_lapse_rate].VarStr, 1))
      ReportError(StrEnv[precip_lapse_rate].KeyName, 51);
  }
  else
    PRECIPLAPSE = NOT_APPLICABLE;
}
