/***************************************************************************** Function name: InitModelState() Purpose : Initialize the state of the model using initial conditions or a saved state from an earlier model run Required : Returns : void Modifies : Comments : Initialize the model state, by reading the state variables from a series of files. This allows restarts of the model from any timestep for which the model state is known. These model states can be stored using the routine StoreModelState(). Timesteps at which to dump the model state can be specified in the file with dump information. *****************************************************************************/ void InitModelState(DATE * Start, MAPSIZE * Map, OPTIONSTRUCT * Options, PRECIPPIX ** PrecipMap, SNOWPIX ** SnowMap, SOILPIX ** SoilMap, LAYER Soil, SOILTABLE * SType, VEGCHEMPIX ** VegChemMap, LAYER Veg, VEGTABLE * VType, char *Path, SNOWTABLE * SnowAlbedo, TOPOPIX ** TopoMap, ROADSTRUCT ** Network, UNITHYDRINFO * HydrographInfo, float *Hydrograph) { const char *Routine = "InitModelState"; char Str[NAMESIZE + 1]; char FileName[NAMESIZE + 1]; FILE *HydroStateFile; int i; /* counter */ int x; /* counter */ int y; /* counter */ int NSet; /* Number of dataset to be read */ int NSoil; /* Number of soil layers for current pixel */ int NVeg; /* Number of veg layers for current pixel */ void *Array; MAPDUMP DMap; /* Dump Info */ float remove; /* Restore canopy interception */ NSet = 0; if (DEBUG) printf("Restoring canopy conditions\n"); sprintf(Str, "%02d.%02d.%02d.%02d.%02d.%02d", Start->Month, Start->Day, Start->Year, Start->Hour, Start->Min, Start->Sec); printf("Reading %sInterception.State.%s%s...\n",Path, Str, fileext); sprintf(FileName, "%sInterception.State.%s%s", Path, Str, fileext); DMap.ID = 202; DMap.Layer = 0; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); if (!(Array = calloc(Map->NY * Map->NX, SizeOfNumberType(DMap.NumberType)))) ReportError((char *) Routine, 1); for (i = 0; i < Veg.MaxLayers; i++) { DMap.ID = 202; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { PrecipMap[y][x].IntRain[i] = 0.0; NVeg = Veg.NLayers[(VegChemMap[y][x].Veg - 1)]; if (i < NVeg) { PrecipMap[y][x].IntRain[i] = ((float *) Array)[y * Map->NX + x]; if (PrecipMap[y][x].IntRain[i] < 0.0) { fprintf(stderr, "InitModelState at (x, y) is (%d, %d):\n", x, y); fprintf(stderr, "\tRain interception negative on layer %d of max %d ... reset to 0\n", i, Veg.MaxLayers); PrecipMap[y][x].IntRain[i] = 0.0; } } } } } } for (i = 0; i < Veg.MaxLayers; i++) { DMap.ID = 203; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++,DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { PrecipMap[y][x].IntSnow[i] = 0.0; NVeg = Veg.NLayers[(VegChemMap[y][x].Veg - 1)]; if (i < NVeg) { PrecipMap[y][x].IntSnow[i] = ((float *) Array)[y * Map->NX + x]; if (PrecipMap[y][x].IntSnow[i] < 0.0) { fprintf(stderr, "InitModelState at (x, y) is (%d, %d):\n", x, y); fprintf(stderr,"Snow interception negative on layer %d of max %d ... reset to 0\n",i, Veg.MaxLayers); PrecipMap[y][x].IntSnow[i] = 0.0; } } } } } } DMap.ID = 204; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++,DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { PrecipMap[y][x].TempIntStorage = ((float *) Array)[y * Map->NX + x]; if (PrecipMap[y][x].TempIntStorage < 0.0) { fprintf(stderr, "InitModelState at (x, y) is (%d, %d):\n", x, y); fprintf(stderr, "Total intercepted precipitation negative on layer %d of max %d ... reset to 0\n", i, Veg.MaxLayers); PrecipMap[y][x].TempIntStorage = 0.0; } } } } free(Array); /* Restore snow pack conditions */ NSet = 0; if (DEBUG) printf("Restoring snow pack conditions\n"); printf("Reading %sSnow.State.%s%s...\n",Path, Str, fileext); sprintf(FileName, "%sSnow.State.%s%s", Path, Str, fileext); DMap.ID = 401; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); if (!(Array = (float *) calloc(Map->NY * Map->NX, SizeOfNumberType(DMap.NumberType)))) ReportError((char *) Routine, 1); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].HasSnow = (unsigned char) ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 403; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].LastSnow = (unsigned short) ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 404; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].Swq = ((float *) Array)[y * Map->NX + x]; //if ( SnowMap[y][x].Swq > 100 ) SnowMap[y][x].Swq = 100; } } } DMap.ID = 406; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].PackWater = ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 407; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].TPack = ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 408; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].SurfWater = ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 409; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].TSurf = ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 410; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SnowMap[y][x].ColdContent = ((float *) Array)[y * Map->NX + x]; } } } free(Array); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (SnowMap[y][x].HasSnow) { SnowMap[y][x].Albedo = CalcSnowAlbedo(SnowMap[y][x].TSurf, SnowMap[y][x].LastSnow, SnowAlbedo); } else { SnowMap[y][x].Albedo = 0; } SnowMap[y][x].ShearStress = 0.0; SnowMap[y][x].IceA = 0.0; SnowMap[y][x].IceFlux = 0.0; SnowMap[y][x].IceVelocity = 0.0; } else { SnowMap[y][x].ShearStress = NA; SnowMap[y][x].IceA = NA; SnowMap[y][x].IceFlux = NA; SnowMap[y][x].Albedo = NA; SnowMap[y][x].IceVelocity = NA; } } } /* Restore soil conditions */ NSet = 0; printf("Reading %sSoil.State.%s%s...\n",Path, Str, fileext); sprintf(FileName, "%sSoil.State.%s%s", Path, Str, fileext); DMap.ID = 501; DMap.Layer = 0; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); if (!(Array = (float *) calloc(Map->NY * Map->NX, SizeOfNumberType(DMap.NumberType)))) ReportError((char *) Routine, 1); for (i = 0; i < Soil.MaxLayers + 1; i++) { DMap.ID = 501; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++,DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NSoil = Soil.NLayers[(SoilMap[y][x].Soil - 1)]; if (i <= NSoil) { SoilMap[y][x].Moist_m_m[i] = ((float *) Array)[y * Map->NX + x]; if (SoilMap[y][x].Moist_m_m[i] < 0.0) { fprintf(stderr, "InitModelState at (x, y) is (%d, %d):\n", x, y); fprintf(stderr,"Soil moisture negative in layer %d of max %d ... reset to 0, was %f\n", i, Soil.MaxLayers, SoilMap[y][x].Moist_m_m[i]); SoilMap[y][x].Moist_m_m[i] = 0.0; } } /* this appears to be redundant - value also set by init-state file jsb 3/4/09 if (i == NSoil) { if (SoilMap[y][x].Moist_m_m[i] < SType[SoilMap[y][x].Soil - 1].FCap[NSoil - 1]) SoilMap[y][x].Moist_m_m[i] = SType[SoilMap[y][x].Soil - 1].FCap[NSoil - 1]; } if (i < NSoil) { if (SoilMap[y][x].Moist_m_m[i] <SType[SoilMap[y][x].Soil - 1].WP[NSoil - 1]) { SoilMap[y][x].Moist_m_m[i] = SType[SoilMap[y][x].Soil - 1].WP[NSoil - 1]; } }*/ } } } } DMap.ID = 505; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SoilMap[y][x].TSurf = ((float *) Array)[y * Map->NX + x]; } } } for (i = 0; i < Soil.MaxLayers; i++) { DMap.ID = 511; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); printf("Reading Soil Temperature State[%d]\n",i); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NSoil = Soil.NLayers[(SoilMap[y][x].Soil - 1)]; if (i < NSoil) SoilMap[y][x].Temp[i] = ((float *) Array)[y * Map->NX + x]; } } } } DMap.ID = 510; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SoilMap[y][x].Qst = ((float *) Array)[y * Map->NX + x]; } } } DMap.ID = 512; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Read2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, NSet++, DMap.Name); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SoilMap[y][x].Runoff_m = ((float *) Array)[y * Map->NX + x]; //DISABLEDTEST: BURPTEST((SoilMap[y][x].Runoff_m<1),"( SoilMap[y][x].Runoff_m <1)"); } } } free(Array); /* Calculate the water table depth at each point based on the soil moisture profile. Give an error message if the water ponds on the surface since that should not be allowed at this point */ remove = 0.0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { /* SatFlow_m needs to be initialized properly in the future. For now it will just be set to zero here */ SoilMap[y][x].SatFlow_m = 0.0; if (INBASIN(TopoMap[y][x].Mask)) { if ((SoilMap[y][x].TableDepth_m = WaterTableDepth((Soil.NLayers[SoilMap[y][x].Soil - 1]),SoilMap[y][x].Depth,VType[VegChemMap[y][x].Veg - 1].RootDepth_m, SType[SoilMap[y][x].Soil - 1].Porosity, SType[SoilMap[y][x].Soil - 1].FCap,Network[y][x].Adjust, SoilMap[y][x].Moist_m_m))< 0.0){ remove -= SoilMap[y][x].TableDepth_m * Map->DX * Map->DY; SoilMap[y][x].TableDepth_m = 0.0; } } else SoilMap[y][x].TableDepth_m = 0; } } if (remove > 0.0) { printf("WARNING:excess water in soil profile is %f m^3 \n", remove); printf("Expect possible large flood wave during first timesteps \n"); } /* If the unit hydrograph is used for flow routing, initialize the unit hydrograph array */ if (Options->Extent == BASIN && Options->HasNetwork == FALSE) { sprintf(FileName, "%sHydrograph.State.%s", Path, Str); OpenFile(&HydroStateFile, FileName, "r", FALSE); for (i = 0; i < HydrographInfo->TotalWaveLength; i++) fscanf(HydroStateFile, "%f\n", &(Hydrograph[i])); fclose(HydroStateFile); } }
/***************************************************************************** Function name: MakeLocalMetData() Purpose : Generates meteorological for each individual cell Required : int y int x MAPSIZE Map int DayStep unsigned char PrecipType int NStats METLOCATION *Stat uchar *MetWeights float LocalElev RADCLASSPIX *RadMap PRECIPPIX *PrecipMap MAPSIZE Radar RADARPIX **RadarMap Returns : PIXMET LocalMet Modifies : Comments : Reference: Shuttleworth, W.J., Evaporation, In: Maidment, D. R. (ed.), Handbook of hydrology, 1993, McGraw-Hill, New York, etc.. *****************************************************************************/ PIXMET MakeLocalMetData(int y, int x, MAPSIZE * Map, int DayStep, OPTIONSTRUCT * Options, int NStats, METLOCATION * Stat, uchar * MetWeights, float LocalElev, RADCLASSPIX * RadMap, PRECIPPIX * PrecipMap, MAPSIZE * Radar, RADARPIX ** RadarMap, float **PrismMap, SNOWPIX * LocalSnow, SNOWTABLE * SnowAlbedo, float ***MM5Input, float ***WindModel, float **PrecipLapseMap, MET_MAP_PIX *** MetMap, int NGraphics, int Month, float skyview, unsigned char shadow, float SunMax, float SineSolarAltitude) { float CurrentWeight; /* weight for current station */ float ScaleWind = 1; /* Wind to be scaled by model factors if WindSource == MODEL */ float Temp; /* Temporary variable */ float WeightSum; /* sum of the weights */ int i; /* counter */ int RadarX; /* X coordinate of radar map coordinate */ int RadarY; /* Y coordinate of radar map coordinate */ float TempLapseRate; int WindDirection = 0; /* Direction of model wind */ PIXMET LocalMet; /* local met data */ LocalMet.Tair = 0.0; LocalMet.Rh = 0.0; LocalMet.Wind = 0.0; LocalMet.Sin = 0.0; LocalMet.SinBeam = 0.0; LocalMet.SinDiffuse = 0.0; LocalMet.Lin = 0.0; TempLapseRate = 0.0; if (Options->MM5 == TRUE && Options->QPF == TRUE) { WeightSum = 0.0; for (i = 0; i < NStats; i++) WeightSum += (float) MetWeights[i]; } if (Options->MM5 == TRUE) { LocalMet.Tair = MM5Input[MM5_temperature - 1][y][x] + (LocalElev - MM5Input[MM5_terrain - 1][y][x]) * MM5Input[MM5_lapse - 1][y][x]; LocalMet.Rh = MM5Input[MM5_humidity - 1][y][x]; LocalMet.Wind = MM5Input[MM5_wind - 1][y][x]; LocalMet.Sin = MM5Input[MM5_shortwave - 1][y][x]; if (Options->Shading == TRUE) { if (SunMax > 0.0) { SeparateRadiation(LocalMet.Sin, LocalMet.Sin / SunMax, &(LocalMet.SinBeam), &(LocalMet.SinDiffuse)); } else { /* if sun is below horizon, the force all shortwave to zero */ LocalMet.Sin = 0.0; LocalMet.SinBeam = 0.0; LocalMet.SinDiffuse = 0.0; } } LocalMet.Lin = MM5Input[MM5_longwave - 1][y][x]; LocalMet.Press = 101300.0; PrecipMap->Precip = MM5Input[MM5_precip - 1][y][x]; /* if(LocalMet.Sin>0) { printf("LocalMet.Sin, LocalMet.Lin are: %f %f \n",LocalMet.Sin, LocalMet.Lin); } */ } else { /* MM5 is false and we need to interpolate the basic met records */ WeightSum = 0.0; for (i = 0; i < NStats; i++) { WeightSum += (float) MetWeights[i]; if (Options->WindSource == MODEL && Stat[i].IsWindModelLocation) { ScaleWind = Stat[i].Data.Wind; WindDirection = Stat[i].Data.WindDirection; } } for (i = 0; i < NStats; i++) { CurrentWeight = ((float) MetWeights[i]) / WeightSum; LocalMet.Tair += CurrentWeight * LapseT(Stat[i].Data.Tair, Stat[i].Elev, LocalElev, Stat[i].Data.TempLapse); LocalMet.Rh += CurrentWeight * Stat[i].Data.Rh; if (Options->WindSource == STATION) LocalMet.Wind += CurrentWeight * Stat[i].Data.Wind; LocalMet.Lin += CurrentWeight * Stat[i].Data.Lin; LocalMet.Sin += CurrentWeight * Stat[i].Data.Sin; if (Options->Shading == TRUE) { LocalMet.SinBeam += CurrentWeight * Stat[i].Data.SinBeamObs; LocalMet.SinDiffuse += CurrentWeight * Stat[i].Data.SinDiffuseObs; } TempLapseRate += CurrentWeight * Stat[i].Data.TempLapse; } if (Options->WindSource == MODEL) LocalMet.Wind = ScaleWind * WindModel[WindDirection - 1][y][x]; if (Options->PrecipType == RADAR) { RadarY = (int) ((y + Radar->OffsetY) * Map->DY / Radar->DY); RadarX = (int) ((x - Radar->OffsetX) * Map->DX / Radar->DX); PrecipMap->Precip = RadarMap[RadarY][RadarX].Precip; } /* WORK IN PROGRESS, taken from old DHSVM version */ /* Air pressure */ /* In rare cases - i.e. when the lapse rate has a different sign for different met stations - you can end up with a TemplapseRate of 0.0 This will result in a crash, so a check was put in (Jul 28, 1997 - Bart Nijssen). It is somewhat awkward to interpolate lapse rates anyway, so a better way of doing this would be welcome */ if (TempLapseRate != 0.0) { Temp = 9.8067 / (TempLapseRate * 287.0); LocalMet.Press = 101300. * pow(((288.0 - TempLapseRate * LocalElev) / 288.0), Temp); } else LocalMet.Press = 101300.; } /* end of else MM5==TRUE, i.e. all basic met, except for precip */ /* has been interpolated */ /* Here is how the following section works */ /* Arc-Info (through use of the hillshade command) will give */ /* an output file that ranges from 0 to 255 (the shade factor) */ /* These correspond to the reflectance of the direct beam radiation */ /* for a given sun position (altitude and azimuth) taking */ /* into account the slope and aspect and topographic shading */ /* of the local pixel. If we wanted to use this value directly */ /* then the correction to the observed beam w.r.t. a horizontal plane */ /* would be actual = horizontal*shadefactor/255/sin(solar_altitude) */ /* the sin(solar_altitude) is necessary to convert horizontal into the maximum */ /* possible flux */ /* We can either have DHSVM make the solar_altitude calculation, which */ /* is not all that hard, but is prone to user error (e.g. GMT time shifts, etc) */ /* or we can simply include the solar_altitude info in the shade_factor */ /* the question is how do we include the sin(solar_altitude) while */ /* keeping new_shade_factor = shadefactor/255/sin(solar_altitude) defined */ /* as a unsigned character */ /* Answer: At sal = 5 degrees max_new_shadefactor = 11.47 */ /* i.e. the actual flux normal to sal is 11.47*observed_horizontal_flux */ /* if we adopt this 5 degree value as a cutoff, we can then be assured that */ /* 0<=newshadefactor<=11.47 and then scale it between 0 and 255 */ /* the final calculation becomes, */ /* actual = horizontal*(float)shadefactor/255.0*11.47 or simply acutal = horizontal*(float)shadefactor/22.23191 */ /* thus radiation increases from 0 to 11.47 times the observed value in */ /* increments of 4.5 percent */ /* a finer resolution than this would require a higher min angle or more memory */ if (Options->Shading == TRUE) { LocalMet.SinBeam = LocalMet.Sin * (float) shadow / 22.23191; LocalMet.SinDiffuse *= skyview; if (LocalMet.SinBeam + LocalMet.SinDiffuse > SOLARCON) LocalMet.SinBeam = SOLARCON - LocalMet.SinDiffuse; } else { LocalMet.SinBeam = LocalMet.Sin; LocalMet.SinDiffuse = 0; } RadMap->Beam = LocalMet.SinBeam; RadMap->Diffuse = LocalMet.SinDiffuse; LocalMet.Sin = RadMap->Beam + RadMap->Diffuse; if (Options->QPF == TRUE || Options->MM5 == FALSE) { if (Options->PrecipType == STATION && Options->Prism == FALSE) { PrecipMap->Precip = 0.0; for (i = 0; i < NStats; i++) { CurrentWeight = ((float) MetWeights[i]) / WeightSum; if (Options->PrecipLapse == MAP) PrecipMap->Precip += CurrentWeight * LapsePrecip(Stat[i].Data.Precip, 0, 1, PrecipLapseMap[y][x]); else PrecipMap->Precip += CurrentWeight * LapsePrecip(Stat[i].Data.Precip, Stat[i].Elev, LocalElev, Stat[i].Data.PrecipLapse); } } else if (Options->PrecipType == STATION && Options->Prism == TRUE) { PrecipMap->Precip = 0.0; for (i = 0; i < NStats; i++) { CurrentWeight = ((float) MetWeights[i]) / WeightSum; /* this is the real prism interpolation */ /* note that X = position from left boundary, ie # of columns */ /* note that Y = position from upper boundary, ie # of rows */ if (Options->Outside == FALSE) PrecipMap->Precip += CurrentWeight * Stat[i].Data.Precip / PrismMap[Stat[i].Loc.N][Stat[i].Loc.E] * PrismMap[y][x]; else PrecipMap->Precip += CurrentWeight * Stat[i].Data.Precip / Stat[i].PrismPrecip[Month - 1] * PrismMap[y][x]; if(PrismMap[y][x] < 0){ printf("negative PrismMap value in MakeLocalMetData.c\n"); exit(0); } } } } /* due to the nature of the interpolation scheme in DHSVM and the */ /* interpolation scheme to handle the mess of different formats of met stations */ /* in the PRISM project */ /* relative humidities can be quite low when precip is occuring */ /* at times this will results in PET being greater than precip */ /* allow an option in DHSVM to override RH if Precip is occuring */ if (Options->Rhoverride == TRUE) { if (PrecipMap->Precip > 0.0) LocalMet.Rh = 100.0; } /* Separate precipitation into rainfall and snowfall */ if (PrecipMap->Precip > 0.0 && LocalMet.Tair < MAX_SNOW_TEMP) { if (LocalMet.Tair > MIN_RAIN_TEMP) PrecipMap->SnowFall = PrecipMap->Precip * (MAX_SNOW_TEMP - LocalMet.Tair) / (MAX_SNOW_TEMP - MIN_RAIN_TEMP); else PrecipMap->SnowFall = PrecipMap->Precip; } else PrecipMap->SnowFall = 0.0; PrecipMap->RainFall = PrecipMap->Precip - PrecipMap->SnowFall; /* Local heat of vaporization, Eq. 4.2.1, Shuttleworth (1993) */ LocalMet.Lv = 2501000 - 2361 * LocalMet.Tair; /* Psychrometric constant */ LocalMet.Gamma = CP * LocalMet.Press / (EPS * LocalMet.Lv); /* Saturated vapor pressure, Eq. 4.2.2, Shuttleworth (1993) */ LocalMet.Es = SatVaporPressure(LocalMet.Tair); /* Slope of vapor pressure curve, Eq. 4.2.3, Shuttleworth (1993) */ LocalMet.Slope = 4098.0 * LocalMet.Es / ((237.3 + LocalMet.Tair) * (237.3 + LocalMet.Tair)); /* Actual vapor pressure */ LocalMet.Eact = LocalMet.Es * (LocalMet.Rh / 100.); /* Vapor pressure deficit */ LocalMet.Vpd = LocalMet.Es - LocalMet.Eact; /* Air density, Eq. 4.2.4 Shuttleworth (1993) */ LocalMet.AirDens = 0.003486 * LocalMet.Press / (275 + LocalMet.Tair); if (LocalSnow->HasSnow) { if (PrecipMap->SnowFall > 0.0) LocalSnow->LastSnow = 0; else LocalSnow->LastSnow++; LocalSnow->Albedo = CalcSnowAlbedo(LocalSnow->TSurf, LocalSnow->LastSnow, SnowAlbedo); } else LocalSnow->LastSnow = 0; if (NGraphics > 0) { (*MetMap)[y][x].accum_precip = (*MetMap)[y][x].accum_precip + PrecipMap->Precip; (*MetMap)[y][x].air_temp = LocalMet.Tair; (*MetMap)[y][x].wind_speed = LocalMet.Wind; (*MetMap)[y][x].humidity = LocalMet.Rh; } return LocalMet; }