/***************************************************************************** InitPrecipMap() *****************************************************************************/ void InitPrecipMap(MAPSIZE * Map, PRECIPPIX *** PrecipMap, VEGPIX ** VegMap, LAYER * Veg, TOPOPIX ** TopoMap) { const char *Routine = "InitPrecipMap"; int x; /* counter */ int y; /* counter */ int NVeg; /* Number of veg layers at current pixel */ if (DEBUG) printf("Initializing precipitation map\n"); if (!(*PrecipMap = (PRECIPPIX **) calloc(Map->NY, sizeof(PRECIPPIX *)))) ReportError((char *) Routine, 1); for (y = 0; y < Map->NY; y++) { if (!((*PrecipMap)[y] = (PRECIPPIX *) calloc(Map->NX, sizeof(PRECIPPIX)))) ReportError((char *) Routine, 1); } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NVeg = Veg->NLayers[(VegMap[y][x].Veg - 1)]; if (!((*PrecipMap)[y][x].IntRain = (float *) calloc(NVeg, sizeof(float)))) ReportError((char *) Routine, 1); } } } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NVeg = Veg->NLayers[(VegMap[y][x].Veg - 1)]; if (!((*PrecipMap)[y][x].IntSnow = (float *) calloc(NVeg, sizeof(float)))) ReportError((char *) Routine, 1); } } } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) (*PrecipMap)[y][x].PrecipStart = TRUE; } } }
/* ------------------------------------------------------------- HeadSlopeAspect This computes slope and aspect using the water table elevation. Comment: rewritten to fill the sinks (Ning, 2013) ------------------------------------------------------------- */ void HeadSlopeAspect(MAPSIZE * Map, TOPOPIX ** TopoMap, SOILPIX ** SoilMap, float **FlowGrad, unsigned char ***Dir, unsigned int **TotalDir) { int x; int y; int n; float neighbor_elev[NNEIGHBORS]; /* let's assume for now that WaterLevel is the SOILPIX map is computed elsewhere */ for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++) { if (INBASIN(TopoMap[y][x].Mask)) { float slope, aspect; for (n = 0; n < NNEIGHBORS; n++) { int xn = x + xneighbor[n]; int yn = y + yneighbor[n]; if (valid_cell(Map, xn, yn)) { neighbor_elev[n] = ((TopoMap[yn][xn].Mask) ? SoilMap[yn][xn].WaterLevel : (float) OUTSIDEBASIN); } else { neighbor_elev[n] = (float) OUTSIDEBASIN; } } slope_aspect(Map->DX, Map->DY, SoilMap[y][x].WaterLevel, neighbor_elev, &slope, &aspect); flow_fractions(Map->DX, Map->DY, slope, aspect, neighbor_elev, &(FlowGrad[y][x]), Dir[y][x], &(TotalDir[y][x])); } } } return; }
/***************************************************************************** InitEvapMap() *****************************************************************************/ void InitEvapMap(MAPSIZE *Map, EVAPPIX ***EvapMap, SOILPIX **SoilMap, LAYER *Soil, VEGPIX **VegMap, LAYER *Veg, TOPOPIX **TopoMap) { const char *Routine = "InitEvapMap"; int i; /* counter */ int x; /* counter */ int y; /* counter */ int NSoil; /* Number of soil layers for current pixel */ int NVeg; /* Number of veg layers for current pixel */ if (DEBUG) printf("Initializing evaporation map\n"); if (!(*EvapMap = (EVAPPIX **) calloc(Map->NY, sizeof(EVAPPIX *)))) ReportError((char *) Routine, 1); for (y = 0; y < Map->NY; y++) { if (!((*EvapMap)[y] = (EVAPPIX *) calloc(Map->NX, sizeof(EVAPPIX)))) ReportError((char *) Routine, 1); } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NVeg = Veg->NLayers[(VegMap[y][x].Veg - 1)]; NSoil = Soil->NLayers[(SoilMap[y][x].Soil - 1)]; assert(VegMap[y][x].Veg > 0 && SoilMap[y][x].Soil > 0); if (!((*EvapMap)[y][x].EPot = (float *) calloc(NVeg + 1, sizeof(float)))) ReportError((char *) Routine, 1); if (!((*EvapMap)[y][x].EAct = (float *) calloc(NVeg + 1, sizeof(float)))) ReportError((char *) Routine, 1); if (!((*EvapMap)[y][x].EInt = (float *) calloc(NVeg, sizeof(float)))) ReportError((char *) Routine, 1); if (!((*EvapMap)[y][x].ESoil = (float **) calloc(NVeg, sizeof(float *)))) ReportError((char *) Routine, 1); for (i = 0; i < NVeg; i++) { if (!((*EvapMap)[y][x].ESoil[i] = (float *) calloc(NSoil, sizeof(float)))) ReportError((char *) Routine, 1); } } } } }
/***************************************************************************** RouteCulvertSediment() *****************************************************************************/ void RouteCulvertSediment(CHANNEL * ChannelData, MAPSIZE * Map, TOPOPIX ** TopoMap, SEDPIX ** SedMap, AGGREGATED * Total, float *SedDiams) { int x, y; float CulvertSedFlow; /* culvert flow of sediment, kg */ int i; Total->CulvertReturnSedFlow = 0.0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { for(i=0; i<NSEDSIZES; i++) { CulvertSedFlow = ChannelCulvertSedFlow(y, x, ChannelData, i); CulvertSedFlow /= Map->DX * Map->DY; if (channel_grid_has_channel(ChannelData->stream_map, x, y)) { /* Percent delivery to streams is conservative and based on particle size */ if (SedDiams[i] <= 0.063){ ChannelData->stream_map[x][y]->channel->sediment.overlandinflow[i] += CulvertSedFlow; Total->CulvertSedToChannel += CulvertSedFlow; CulvertSedFlow = 0.; } if ((SedDiams[i] > 0.063) && (SedDiams[i] <= 0.5)){ ChannelData->stream_map[x][y]->channel->sediment.overlandinflow[i] += 0.3*CulvertSedFlow; Total->CulvertSedToChannel += 0.3*CulvertSedFlow; Total->CulvertReturnSedFlow += 0.7*CulvertSedFlow; CulvertSedFlow = 0.; } if ((SedDiams[i] > 0.5) && (SedDiams[i] <= 2.)){ ChannelData->stream_map[x][y]->channel->sediment.overlandinflow[i] += 0.1*CulvertSedFlow; Total->CulvertSedToChannel += 0.1*CulvertSedFlow; Total->CulvertReturnSedFlow += 0.9*CulvertSedFlow; CulvertSedFlow = 0.; } Total->CulvertReturnSedFlow += CulvertSedFlow; } else { Total->CulvertReturnSedFlow += CulvertSedFlow; } } } } } }
/***************************************************************************** RouteSubSurface() Sources: Wigmosta, M. S., L. W. Vail, and D. P. Lettenmaier, A distributed hydrology-vegetation model for complex terrain, Water Resour. Res., 30(6), 1665-1679, 1994. Quinn, P., K. Beven, P. Chevallier, and O. Planchon, The prediction of hillslope flow paths for distributed hydrological modelling using digital terrain models, Hydrological Processes, 5, 59-79, 1991. This routine follows Wigmosta et al. [1994] in calculating the subsurface flow. The local gradient is based on the local hydraulic head, consisting of the height of the pixel surface minus the depth of the water table below the water surface. This has the disadvantage that the local gradients have to be recalculated for each pixel for each timestep. In Wigmosta et al. [1994] the local gradient is taken to be equal to the slope of the land surface, which is a reasonable assunption for mountainous areas. For the flat boreal forest landscape it is probably better to use the slope of the water surface. Set the gradient with pixels that are outside tha basin to zero. This ensures that there is no flux of water across the basin boundary. In the current implementation water can only leave the basin as surface flow. This may not be entirely realistic, and should be analyzed further. One consequence of this could be that the soil in the basin is more saturated than it would be if subsurface flow out of the basin would be allowed. The surrounding grid cells are numbered in the following way |-----| DX 0-----1-----2 --- |\ | /| | | \ | / | | | \ | / | | DY | \ | / | | | \|/ | | 7-----*-----3 --- | /|\ | | / | \ | | / | \ | | / | \ | |/ | \| 6-----5-----4 For the current implementation it is assumed that the resolution is the same in both the X and the Y direction. If this is not the case an error message is generated and the program exits. The reason is that the formulation for the flow width in the diagonal direction changes if the grid is not square. The method for defining the flow widths in the case of square grids is taken from Quinn et al [1991] Update Jan 2004 COD When Gradient = WATERTABLE, the watertable was used to route the surface water. This was because of the common use of TopoMap.Dir and TopoMap.TotalDir. These are now for surface routing (always) and subsurface routing (when Gradient = TOPOGRAPHY). Subsurface routing directions and FlowGrad (SubDir, SubTotalDir, SubFlowGrad) for Gradient = WATERTABLE are now determined locally here (in RouteSubsurface.c.) WORK IN PROGRESS *****************************************************************************/ void RouteSubSurface(int Dt, MAPSIZE *Map, TOPOPIX **TopoMap, VEGTABLE *VType, VEGPIX **VegMap, ROADSTRUCT **Network, SOILTABLE *SType, SOILPIX **SoilMap, CHANNEL *ChannelData, TIMESTRUCT *Time, OPTIONSTRUCT *Options, char *DumpPath, SEDPIX **SedMap, FINEPIX ***FineMap, SEDTABLE *SedType, int MaxStreamID, SNOWPIX **SnowMap) { const char *Routine = "RouteSubSurface"; int x; /* counter */ int y; /* counter */ int i,j, ii, jj, yy, xx; /* counters for FineMap initialization */ float BankHeight; float *Adjust; float fract_used; float depth; float OutFlow; float water_out_road; float Transmissivity; float AvailableWater; int k; float **SubFlowGrad; /* Magnitude of subsurface flow gradient slope * width */ unsigned char ***SubDir; /* Fraction of flux moving in each direction*/ unsigned int **SubTotalDir; /* Sum of Dir array */ /* variables for mass wasting trigger. */ int count, totalcount; float mgrid, sat; char buffer[32]; char satoutfile[100]; /* Character arrays to hold file name. */ FILE *fs; /* File pointer. */ /***************************************************************************** Allocate memory ****************************************************************************/ if (!(SubFlowGrad = (float **)calloc(Map->NY, sizeof(float *)))) ReportError((char *) Routine, 1); for(i=0; i<Map->NY; i++) { if (!(SubFlowGrad[i] = (float *)calloc(Map->NX, sizeof(float)))) ReportError((char *) Routine, 1); } if (!((SubDir) = (unsigned char ***) calloc(Map->NY, sizeof(unsigned char **)))) ReportError((char *) Routine, 1); for(i=0; i<Map->NY; i++) { if (!((SubDir)[i] = (unsigned char **) calloc(Map->NX, sizeof(unsigned char*)))) ReportError((char *) Routine, 1); for(j=0; j<Map->NX; j++) { if (!(SubDir[i][j] = (unsigned char *)calloc(NDIRS, sizeof(unsigned char )))) ReportError((char *) Routine, 1); } } if (!(SubTotalDir = (unsigned int **)calloc(Map->NY, sizeof(unsigned int *)))) ReportError((char *) Routine, 1); for(i=0; i<Map->NY; i++) { if (!(SubTotalDir[i] = (unsigned int *)calloc(Map->NX, sizeof(unsigned int)))) ReportError((char *) Routine, 1); } /* reset the saturated subsurface flow to zero */ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SoilMap[y][x].SatFlow = 0; /* ChannelInt and RoadInt are initialized in Aggregate.c Why are there here? */ /* SoilMap[y][x].ChannelInt = 0; */ SoilMap[y][x].RoadInt = 0; } } } if (Options->FlowGradient == WATERTABLE) HeadSlopeAspect(Map, TopoMap, SoilMap, SubFlowGrad, SubDir, SubTotalDir); /* next sweep through all the grid cells, calculate the amount of flow in each direction, and divide the flow over the surrounding pixels */ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (Options->FlowGradient == TOPOGRAPHY){ SubTotalDir[y][x] = TopoMap[y][x].TotalDir; SubFlowGrad[y][x] = TopoMap[y][x].FlowGrad; for (k = 0; k < NDIRS; k++) SubDir[y][x][k] = TopoMap[y][x].Dir[k]; } BankHeight = (Network[y][x].BankHeight > SoilMap[y][x].Depth) ? SoilMap[y][x].Depth : Network[y][x].BankHeight; Adjust = Network[y][x].Adjust; fract_used = 0.0f; water_out_road = 0.0; if (!channel_grid_has_channel(ChannelData->stream_map, x, y)) { for (k = 0; k < NDIRS; k++) { fract_used += (float) SubDir[y][x][k]; /* fract_used += (float) TopoMap[y][x].Dir[k]; */ } /* fract_used /= 255.0f; */ /* fract_used /= (float) TopoMap[y][x].TotalDir; */ if (SubTotalDir[y][x] > 0) fract_used /= (float) SubTotalDir[y][x]; else fract_used = 0.; /* only bother calculating subsurface flow if water table is above bedrock */ if (SoilMap[y][x].TableDepth < SoilMap[y][x].Depth) { depth = ((SoilMap[y][x].TableDepth > BankHeight) ? SoilMap[y][x].TableDepth : BankHeight); Transmissivity = CalcTransmissivity(SoilMap[y][x].Depth, depth, SType[SoilMap[y][x].Soil - 1].KsLat, SType[SoilMap[y][x].Soil - 1].KsLatExp, SType[SoilMap[y][x].Soil - 1].DepthThresh); OutFlow = (Transmissivity * fract_used * SubFlowGrad[y][x] * Dt) / (Map->DX * Map->DY); /* (Transmissivity * fract_used * TopoMap[y][x].FlowGrad * Dt) / */ /* (Map->DX * Map->DY); */ /* check whether enough water is available for redistribution */ AvailableWater = CalcAvailableWater(VType[VegMap[y][x].Veg - 1].NSoilLayers, SoilMap[y][x].Depth, VType[VegMap[y][x].Veg - 1].RootDepth, SType[SoilMap[y][x].Soil - 1].Porosity, SType[SoilMap[y][x].Soil - 1].FCap, SoilMap[y][x].TableDepth, Adjust); OutFlow = (OutFlow > AvailableWater) ? AvailableWater : OutFlow; } else { depth = SoilMap[y][x].Depth; OutFlow = 0.0f; } /* compute road interception if water table is above road cut */ if (SoilMap[y][x].TableDepth < BankHeight && channel_grid_has_channel(ChannelData->road_map, x, y)) { /* fract_used = ((float) Network[y][x].fraction / 255.0f); */ /* fract_used = ((float) Network[y][x].fraction / (float)TopoMap[y][x].TotalDir); */ if (SubTotalDir[y][x] > 0) fract_used = ((float) Network[y][x].fraction / (float)SubTotalDir[y][x]); else fract_used = 0.; Transmissivity = CalcTransmissivity(BankHeight, SoilMap[y][x].TableDepth, SType[SoilMap[y][x].Soil - 1].KsLat, SType[SoilMap[y][x].Soil - 1].KsLatExp, SType[SoilMap[y][x].Soil - 1].DepthThresh); water_out_road = (Transmissivity * fract_used * SubFlowGrad[y][x] * Dt) / (Map->DX * Map->DY); /* (Transmissivity * fract_used * */ /* TopoMap[y][x].FlowGrad * Dt) / (Map->DX * */ /* Map->DY); */ AvailableWater = CalcAvailableWater(VType[VegMap[y][x].Veg - 1].NSoilLayers, BankHeight, VType[VegMap[y][x].Veg - 1].RootDepth, SType[SoilMap[y][x].Soil - 1].Porosity, SType[SoilMap[y][x].Soil - 1].FCap, SoilMap[y][x].TableDepth, Adjust); water_out_road = (water_out_road > AvailableWater) ? AvailableWater : water_out_road; /* increase lateral inflow to road channel */ SoilMap[y][x].RoadInt = water_out_road; channel_grid_inc_inflow(ChannelData->road_map, x, y, water_out_road * Map->DX * Map->DY); } /* Subsurface Component - Decrease water change by outwater */ SoilMap[y][x].SatFlow -= OutFlow + water_out_road; /* Assign the water to appropriate surrounding pixels */ /* OutFlow /= 255.0f; */ /* OutFlow /= (float) TopoMap[y][x].TotalDir; */ if (SubTotalDir[y][x] > 0) OutFlow /= (float) SubTotalDir[y][x]; else OutFlow = 0.; for (k = 0; k < NDIRS; k++) { int nx = xdirection[k] + x; int ny = ydirection[k] + y; if (valid_cell(Map, nx, ny)) { SoilMap[ny][nx].SatFlow += OutFlow * SubDir[y][x][k]; /* SoilMap[ny][nx].SatFlow += OutFlow * TopoMap[y][x].Dir[k]; */ } } } else { /* cell has a stream channel */ if (SoilMap[y][x].TableDepth < BankHeight && channel_grid_has_channel(ChannelData->stream_map, x, y)) { /* float gradient = */ /* (4.0 * SoilMap[y][x].Depth > 2.0 * MIN_GRAD * Map->DX) ? */ /* 4.0 * SoilMap[y][x].Depth : 2.0 * MIN_GRAD * Map->DX; */ float gradient = 4.0 * (BankHeight - SoilMap[y][x].TableDepth); if (gradient < 0.0) gradient = 0.0; Transmissivity = CalcTransmissivity(BankHeight, SoilMap[y][x].TableDepth, SType[SoilMap[y][x].Soil - 1].KsLat, SType[SoilMap[y][x].Soil - 1].KsLatExp, SType[SoilMap[y][x].Soil - 1].DepthThresh); OutFlow = (Transmissivity * gradient * Dt) / (Map->DX * Map->DY); /* check whether enough water is available for redistribution */ AvailableWater = CalcAvailableWater(VType[VegMap[y][x].Veg - 1].NSoilLayers, BankHeight, VType[VegMap[y][x].Veg - 1].RootDepth, SType[SoilMap[y][x].Soil - 1].Porosity, SType[SoilMap[y][x].Soil - 1].FCap, SoilMap[y][x].TableDepth, Adjust); OutFlow = (OutFlow > AvailableWater) ? AvailableWater : OutFlow; /* remove water going to channel from the grid cell */ SoilMap[y][x].SatFlow -= OutFlow; /* contribute to channel segment lateral inflow */ channel_grid_inc_inflow(ChannelData->stream_map, x, y, OutFlow * Map->DX * Map->DY); SoilMap[y][x].ChannelInt += OutFlow; } } } } } for(i=0; i<Map->NY; i++) { free(SubTotalDir[i]); free(SubFlowGrad[i]); for(j=0; j<Map->NX; j++){ free(SubDir[i][j]); } free(SubDir[i]); } free(SubDir); free(SubTotalDir); free(SubFlowGrad); /**********************************************************************/ /* Dump saturation extent file to screen for Mass Wasting dates. Saturation extent is based on the number of pixels with a water table that is at least MTHRESH of soil depth. */ count =0; totalcount = 0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { mgrid = (SoilMap[y][x].Depth - SoilMap[y][x].TableDepth)/SoilMap[y][x].Depth; if(mgrid > MTHRESH) count += 1; totalcount +=1; } } } sat = 100.*((float)count/(float)totalcount); sprintf(satoutfile, "%ssaturation_extent.txt", DumpPath); if((fs=fopen(satoutfile,"a")) == NULL){ printf("Cannot open saturation extent output file.\n"); exit(0); } SPrintDate(&(Time->Current), buffer); fprintf(fs, "%-20s %.4f \n", buffer, sat); fclose(fs); /* Initialize the mass wasting variables for all time steps to maintain the mass balance */ if(Options->Sediment){ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { for(ii=0; ii< Map->DY/Map->DMASS; ii++) { /* Fine resolution counters. */ for(jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; (*FineMap[yy][xx]).Probability = 0.; (*FineMap[yy][xx]).MassWasting = 0.; (*FineMap[yy][xx]).MassDeposition = 0.; (*FineMap[yy][xx]).SedimentToChannel = 0.; } } } } } /* Call the mass wasting algorithm */ if(Options->MassWaste){ if(Time->NMWMTotalSteps > 0){ if(Time->Current.Julian == Time->MWMnext.Julian){ MainMWM(SedMap, FineMap, VType, SedType, ChannelData, DumpPath, SoilMap, Time, Map, TopoMap, SType, VegMap, MaxStreamID, SnowMap); /* catch the next date */ for (i = 0; i < Time->NMWMTotalSteps; i++){ if(Time->MWMnext.Julian < Time->MWM[i].Julian){ Time->MWMnext = Time->MWM[i]; break; } } } } else{ /* Time->NMWMTotalSteps == 0 run the old way*/ if((float)count/((float)totalcount) > SATPERCENT) { MainMWM(SedMap, FineMap, VType, SedType, ChannelData, DumpPath, SoilMap, Time, Map, TopoMap, SType, VegMap, MaxStreamID, SnowMap); } } } } /**********************************************************************/ /* End added code. */ }
/***************************************************************************** Function name: CalcWeights() Purpose : Calculate interpolation weights to interpolate the meteorological data from the various stations for every individual pixel Required : METLOCATION *Station - Location of meteorological stations int NStats - Number of meteorological stations int NX - Number of pixels in East - West direction int NY - Number of pixels in North - South direction uchar ** BasinMask - BasinMask uchar ***WeightArray - 3D array with interpolation weights Returns : void Modifies : The values stored at the addresses pointed to by WeightArray (i.e. it calculates the weights and stores them) Comments : *****************************************************************************/ void CalcWeights(METLOCATION * Station, int NStats, int NX, int NY, uchar ** BasinMask, uchar **** WeightArray, OPTIONSTRUCT * Options) { double *Weights; /* Array with weights for all stations */ double *Distance; /* Array with distances to all stations */ double *InvDist2; /* Array with inverse distance squared */ double Denominator; /* Sum of 1/Distance^2 */ double mindistance; double avgdistance; double tempdistance; double cr, crt; int totalweight; int y; /* Counter for rows */ int x; /* Counter for columns */ int i, j; /* Counter for stations */ int CurrentStation; /* Station at current location (if any) */ int *stationid; /* index array for sorted list of station distances */ int *stat; int tempid; int closest; int crstat; COORD Loc; /* Location of current point */ /* Allocate memory for a 3 dimensional array */ if (DEBUG) printf("Calculating interpolation weights for %d stations\n", NStats); if (!((*WeightArray) = (uchar ***) calloc(NY, sizeof(uchar **)))) ReportError("CalcWeights()", 1); for (y = 0; y < NY; y++) if (!((*WeightArray)[y] = (uchar **) calloc(NX, sizeof(uchar *)))) ReportError("CalcWeights()", 1); for (y = 0; y < NY; y++) for (x = 0; x < NX; x++) if (!((*WeightArray)[y][x] = (uchar *) calloc(NStats, sizeof(uchar)))) ReportError("CalcWeights()", 1); /* Allocate memory for the array that will contain weights, and the array for the distances to each of the towers, and the inverse distance squared */ if (!(Weights = (double *) calloc(NStats, sizeof(double)))) ReportError("CalcWeights()", 1); if (!(Distance = (double *) calloc(NStats, sizeof(double)))) ReportError("CalcWeights()", 1); if (!(InvDist2 = (double *) calloc(NStats, sizeof(double)))) ReportError("CalcWeights()", 1); if (!(stationid = (int *) calloc(NStats, sizeof(int)))) ReportError("CalcWeights()", 1); if (!(stat = (int *) calloc(NStats + 1, sizeof(int)))) ReportError("CalcWeights()", 1); /* Calculate the weights for each location that is inside the basin mask */ /* note stations themselves can be outside the mask */ /* this first scheme is an inverse distance squared scheme */ if (Options->Interpolation == INVDIST) { for (y = 0; y < NY; y++) { Loc.N = y; for (x = 0; x < NX; x++) { Loc.E = x; if (INBASIN(BasinMask[y][x])) { if (IsStationLocation(&Loc, NStats, Station, &CurrentStation)) { for (i = 0; i < NStats; i++) { if (i == CurrentStation) (*WeightArray)[y][x][i] = MAXUCHAR; else (*WeightArray)[y][x][i] = 0; } } else { for (i = 0, Denominator = 0; i < NStats; i++) { Distance[i] = CalcDistance(&(Station[i].Loc), &Loc); InvDist2[i] = 1 / (Distance[i] * Distance[i]); Denominator += InvDist2[i]; } for (i = 0; i < NStats; i++) { (*WeightArray)[y][x][i] = (uchar) Round(InvDist2[i] / Denominator * MAXUCHAR); } } } else { for (i = 0; i < NStats; i++) (*WeightArray)[y][x][i] = 0; } } } } if (Options->Interpolation == NEAREST) { /* this next scheme is a nearest station */ printf("Number of stations is %d \n", NStats); for (y = 0; y < NY; y++) { Loc.N = y; for (x = 0; x < NX; x++) { Loc.E = x; if (INBASIN(BasinMask[y][x])) { /*we are inside the basin mask */ /* find the distance to nearest station */ mindistance = DHSVM_HUGE; avgdistance = 0.0; for (i = 0; i < NStats; i++) { Distance[i] = CalcDistance(&(Station[i].Loc), &Loc); avgdistance += Distance[i] / ((double) NStats); if (Distance[i] < mindistance) { mindistance = Distance[i]; closest = i; } } /* got closest station */ for (i = 0; i < NStats; i++) { if (i == closest) (*WeightArray)[y][x][i] = MAXUCHAR; else (*WeightArray)[y][x][i] = 0; } } /* done in basin mask */ else { for (i = 0; i < NStats; i++) (*WeightArray)[y][x][i] = 0; } } } } if (Options->Interpolation == VARCRESS) { /* this next scheme is a variable radius cressman */ /* find the distance to the nearest station */ /* make a decision based on the maximum allowable radius, cr */ /* and the distance to the closest station */ /* while limiting the number of interpolation stations to three */ cr = (double) Options->CressRadius; if (cr < 2) ReportError("CalcWeights.c", 42); crstat = Options->CressStations; if (crstat < 2) ReportError("CalcWeights.c", 42); for (y = 0; y < NY; y++) { Loc.N = y; for (x = 0; x < NX; x++) { Loc.E = x; if (INBASIN(BasinMask[y][x])) { /*we are inside the basin mask */ /* find the distance to nearest station */ for (i = 0; i < NStats; i++) { Distance[i] = CalcDistance(&(Station[i].Loc), &Loc); stationid[i] = i; } /* got distances for each station */ /* now sort the list by distance */ for (i = 0; i < NStats; i++) { for (j = 0; j < NStats; j++) { if (Distance[j] > Distance[i]) { tempdistance = Distance[i]; tempid = stationid[i]; Distance[i] = Distance[j]; stationid[i] = stationid[j]; Distance[j] = tempdistance; stationid[j] = tempid; } } } crt = Distance[0] * 2.0; if (crt < 1.0) crt = 1.0; for (i = 0, Denominator = 0; i < NStats; i++) { if (i < crstat && Distance[i] < crt) { InvDist2[i] = (crt * crt - Distance[i] * Distance[i]) / (crt * crt + Distance[i] * Distance[i]); Denominator += InvDist2[i]; } else InvDist2[i] = 0.0; } for (i = 0; i < NStats; i++) (*WeightArray)[y][x][stationid[i]] = (uchar) Round(InvDist2[i] / Denominator * MAXUCHAR); /*at this point all weights have been assigned to one or more stations */ } } } } /*check that all weights add up to MAXUCHAR */ /* and output some stats on the interpolation field */ for (i = 0; i <= NStats; i++) stat[i] = 0; for (i = 0; i < NStats; i++) stationid[i] = 0; printf("\nChecking interpolation weights\n"); printf("Sum should be 255 for all pixels \n"); printf("Some error is expected due to roundoff \n"); printf("Errors greater than +/- 2 Percent are: \n"); for (y = 0; y < NY; y++) { for (x = 0; x < NX; x++) { if (INBASIN(BasinMask[y][x])) { /*we are inside the basin mask */ tempid = 0; totalweight = 0; for (i = 0; i < NStats; i++) { totalweight += (int) (*WeightArray)[y][x][i]; if ((*WeightArray)[y][x][i] > 0) { tempid += 1; stationid[i] = 1; } } if (totalweight < 250 || totalweight > 260) { printf("error in interpolation weight at pixel y %d x %d : %d \n", y, x, totalweight); assert(FALSE); } stat[tempid] += 1; } } } for (i = 0; i <= NStats; i++) if (stat[i] > 0) printf("this many pixels %d are linked to %d met stations \n", stat[i], i); for (i = 0; i < NStats; i++) if (stationid[i] > 0) printf("Station: %s used in interpolation \n", Station[i].Name); /* Free memory */ free(Weights); free(Distance); free(InvDist2); free(stationid); free(stat); }
/***************************************************************************** Aggregate() Calculate the average values for the different fluxes and state variables over the basin. Only the runoff and some of the sediment variables (as noted) are calculated as a totals (i.e. runoff is total volume) instead of an average. In the current implementation the local radiation elements are not stored for the entire area. Therefore these components are aggregated in AggregateRadiation() inside MassEnergyBalance(). The aggregated values are set to zero in the function RestAggregate, which is executed at the beginning of each time step. *****************************************************************************/ void Aggregate(MAPSIZE *Map, OPTIONSTRUCT *Options, TOPOPIX **TopoMap, LAYER *Soil, LAYER * Veg, VEGPIX **VegMap, EVAPPIX **Evap, PRECIPPIX **Precip, RADCLASSPIX **RadMap, SNOWPIX **Snow, SOILPIX **SoilMap, AGGREGATED *Total, VEGTABLE *VType, ROADSTRUCT **Network, SEDPIX **SedMap, FINEPIX ***FineMap, CHANNEL *ChannelData, float *roadarea) { int NPixels; /* Number of pixels in the basin */ int NPixelsfine; /* Number of pixels in the finemap */ int NSoilL; /* Number of soil layers for current pixel */ int NVegL; /* Number of vegetation layers for current pixel */ int i; /* counter */ int j; /* counter */ int x; int y; float DeepDepth; /* depth to bottom of lowest rooting zone */ int ii; /* FineMap counter */ int jj; /* FineMap counter */ int xx; /* x-coordinate on FineMap grid */ int yy; /* y-coordinate on FineMap grid */ NPixels = 0; *roadarea = 0.; NPixelsfine = 0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NPixels++; NSoilL = Soil->NLayers[SoilMap[y][x].Soil - 1]; NVegL = Veg->NLayers[VegMap[y][x].Veg - 1]; /* aggregate the evaporation data */ Total->Evap.ETot += Evap[y][x].ETot; for (i = 0; i < NVegL; i++) { Total->Evap.EPot[i] += Evap[y][x].EPot[i]; Total->Evap.EAct[i] += Evap[y][x].EAct[i]; Total->Evap.EInt[i] += Evap[y][x].EInt[i]; } Total->Evap.EPot[Veg->MaxLayers] += Evap[y][x].EPot[NVegL]; Total->Evap.EAct[Veg->MaxLayers] += Evap[y][x].EAct[NVegL]; for (i = 0; i < NVegL; i++) { for (j = 0; j < NSoilL; j++) { Total->Evap.ESoil[i][j] += Evap[y][x].ESoil[i][j]; } } Total->Evap.EvapSoil += Evap[y][x].EvapSoil; /* aggregate precipitation data */ Total->Precip.Precip += Precip[y][x].Precip; for (i = 0; i < NVegL; i++) { Total->Precip.IntRain[i] += Precip[y][x].IntRain[i]; Total->Precip.IntSnow[i] += Precip[y][x].IntSnow[i]; Total->CanopyWater += Precip[y][x].IntRain[i] + Precip[y][x].IntSnow[i]; } /* aggregate radiation data */ if (Options->MM5 == TRUE) { Total->RadClass.Beam = NOT_APPLICABLE; Total->RadClass.Diffuse = NOT_APPLICABLE; } else { Total->RadClass.Beam += RadMap[y][x].Beam; Total->RadClass.Diffuse += RadMap[y][x].Diffuse; } /* aggregate snow data */ if (Snow[y][x].HasSnow) Total->Snow.HasSnow = TRUE; Total->Snow.Swq += Snow[y][x].Swq; Total->Snow.Glacier += Snow[y][x].Glacier; /* Total->Snow.Melt += Snow[y][x].Melt; */ Total->Snow.Melt += Snow[y][x].Outflow; Total->Snow.PackWater += Snow[y][x].PackWater; Total->Snow.TPack += Snow[y][x].TPack; Total->Snow.SurfWater += Snow[y][x].SurfWater; Total->Snow.TSurf += Snow[y][x].TSurf; Total->Snow.ColdContent += Snow[y][x].ColdContent; Total->Snow.Albedo += Snow[y][x].Albedo; Total->Snow.Depth += Snow[y][x].Depth; Total->Snow.VaporMassFlux += Snow[y][x].VaporMassFlux; Total->Snow.CanopyVaporMassFlux += Snow[y][x].CanopyVaporMassFlux; /* aggregate soil moisture data */ Total->Soil.Depth += SoilMap[y][x].Depth; DeepDepth = 0.0; for (i = 0; i < NSoilL; i++) { Total->Soil.Moist[i] += SoilMap[y][x].Moist[i]; assert(SoilMap[y][x].Moist[i] >= 0.0); Total->Soil.Perc[i] += SoilMap[y][x].Perc[i]; Total->Soil.Temp[i] += SoilMap[y][x].Temp[i]; Total->SoilWater += SoilMap[y][x].Moist[i] * VType[VegMap[y][x].Veg - 1].RootDepth[i] * Network[y][x].Adjust[i]; DeepDepth += VType[VegMap[y][x].Veg - 1].RootDepth[i]; } Total->Soil.Moist[Soil->MaxLayers] += SoilMap[y][x].Moist[NSoilL]; Total->SoilWater += SoilMap[y][x].Moist[NSoilL] * (SoilMap[y][x].Depth - DeepDepth) * Network[y][x].Adjust[NSoilL]; Total->Soil.TableDepth += SoilMap[y][x].TableDepth; if (SoilMap[y][x].TableDepth <= 0) (Total->Saturated)++; Total->Soil.WaterLevel += SoilMap[y][x].WaterLevel; Total->Soil.SatFlow += SoilMap[y][x].SatFlow; Total->Soil.TSurf += SoilMap[y][x].TSurf; Total->Soil.Qnet += SoilMap[y][x].Qnet; Total->Soil.Qs += SoilMap[y][x].Qs; Total->Soil.Qe += SoilMap[y][x].Qe; Total->Soil.Qg += SoilMap[y][x].Qg; Total->Soil.Qst += SoilMap[y][x].Qst; Total->Soil.IExcess += SoilMap[y][x].IExcess; Total->Soil.DetentionStorage += SoilMap[y][x].DetentionStorage; if(Options->RoadRouting){ if (Network[y][x].RoadArea > 0) { for (i = 0; i < CELLFACTOR; i++) Total->Road.IExcess += (Network[y][x].h[i]* Network[y][x].RoadArea)/((float)CELLFACTOR * (Map->DX*Map->DY)); } } if (Options->Infiltration == DYNAMIC) Total->Soil.InfiltAcc += SoilMap[y][x].InfiltAcc; Total->Runoff += SoilMap[y][x].Runoff; Total->ChannelInt += SoilMap[y][x].ChannelInt; SoilMap[y][x].ChannelInt = 0.0; Total->RoadInt += SoilMap[y][x].RoadInt; SoilMap[y][x].RoadInt = 0.0; if(Options->Sediment){ if (Options->SurfaceErosion) { Total->Sediment.Erosion += SedMap[y][x].Erosion; Total->Sediment.SedFluxOut += SedMap[y][x].SedFluxOut; } *roadarea += Network[y][x].RoadArea; Total->Road.Erosion += Network[y][x].Erosion; Total->Sediment.RoadSed += SedMap[y][x].RoadSed; for (ii=0; ii< Map->DY/Map->DMASS; ii++) { for (jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; Total->Fine.SatThickness += (*FineMap[yy][xx]).SatThickness; Total->Fine.DeltaDepth += (*FineMap[yy][xx]).DeltaDepth; Total->Fine.Probability += (*FineMap[yy][xx]).Probability; Total->Fine.MassWasting += (*FineMap[yy][xx]).MassWasting; Total->Fine.MassDeposition += (*FineMap[yy][xx]).MassDeposition; Total->Fine.SedimentToChannel += (*FineMap[yy][xx]).SedimentToChannel; } } } } } } /* divide road area by pixel area so it can be used to calculate depths over the road surface in FinalMassBalancs */ *roadarea /= Map->DX * Map->DY * NPixels; /* calculate average values for all quantities except the surface flow */ /* average evaporation data */ Total->Evap.ETot /= NPixels; for (i = 0; i < Veg->MaxLayers + 1; i++) { Total->Evap.EPot[i] /= NPixels; Total->Evap.EAct[i] /= NPixels; } for (i = 0; i < Veg->MaxLayers; i++) Total->Evap.EInt[i] /= NPixels; for (i = 0; i < Veg->MaxLayers; i++) { for (j = 0; j < Soil->MaxLayers; j++) { Total->Evap.ESoil[i][j] /= NPixels; } } Total->Evap.EvapSoil /= NPixels;; /* average precipitation data */ Total->Precip.Precip /= NPixels; for (i = 0; i < Veg->MaxLayers; i++) { Total->Precip.IntRain[i] /= NPixels; Total->Precip.IntSnow[i] /= NPixels; } Total->CanopyWater /= NPixels; /* average radiation data */ for (i = 0; i < Veg->MaxLayers + 1; i++) { Total->Rad.NetShort[i] /= NPixels; Total->Rad.LongIn[i] /= NPixels; Total->Rad.LongOut[i] /= NPixels; } Total->Rad.PixelNetShort /= NPixels; Total->Rad.PixelLongIn /= NPixels; Total->Rad.PixelLongOut /= NPixels; Total->RadClass.Beam /= NPixels; Total->RadClass.Diffuse /= NPixels; /* average snow data */ Total->Snow.Swq /= NPixels; Total->Snow.Melt /= NPixels; Total->Snow.PackWater /= NPixels; Total->Snow.TPack /= NPixels; Total->Snow.SurfWater /= NPixels; Total->Snow.TSurf /= NPixels; Total->Snow.ColdContent /= NPixels; Total->Snow.Albedo /= NPixels; Total->Snow.Depth /= NPixels; Total->Snow.VaporMassFlux /= NPixels; Total->Snow.CanopyVaporMassFlux /= NPixels; /* average soil moisture data */ Total->Soil.Depth /= NPixels; for (i = 0; i < Soil->MaxLayers; i++) { Total->Soil.Moist[i] /= NPixels; Total->Soil.Perc[i] /= NPixels; Total->Soil.Temp[i] /= NPixels; } Total->Soil.Moist[Soil->MaxLayers] /= NPixels; Total->Soil.TableDepth /= NPixels; Total->Soil.WaterLevel /= NPixels; Total->Soil.SatFlow /= NPixels; Total->Soil.TSurf /= NPixels; Total->Soil.Qnet /= NPixels; Total->Soil.Qs /= NPixels; Total->Soil.Qe /= NPixels; Total->Soil.Qg /= NPixels; Total->Soil.Qst /= NPixels; Total->Soil.IExcess /= NPixels; Total->Soil.DetentionStorage /= NPixels; Total->Road.IExcess /= NPixels; if (Options->Infiltration == DYNAMIC) Total->Soil.InfiltAcc /= NPixels; Total->SoilWater /= NPixels; Total->Runoff /= NPixels; Total->ChannelInt /= NPixels; Total->RoadInt /= NPixels; Total->CulvertReturnFlow /= NPixels; Total->CulvertToChannel /= NPixels; Total->RunoffToChannel /= NPixels; /* Average Sediment results */ if (Options->Sediment) { if (Options->SurfaceErosion){ Total->Sediment.Erosion /= NPixels; Total->Sediment.SedFluxOut /= NPixels; } Total->Road.Erosion /= NPixels; Total->Sediment.RoadSed /= NPixels; // FineMap quantities must be averaged over number of FineMap cells // rather than over the number of coarse grid cells Total->Fine.SatThickness /= (NPixels*Map->DMASS*Map->DMASS); Total->Fine.DeltaDepth /= (NPixels*Map->DMASS*Map->DMASS); Total->Fine.Probability /= (NPixels*Map->DMASS*Map->DMASS); // (We don't divide SedimentToChannel, MassWasting, etc. by NPixels, // since they are totals and not averages) } }
/* ------------------------------------------------------------- RouteChannel ------------------------------------------------------------- */ void RouteChannel(CHANNEL * ChannelData, TIMESTRUCT * Time, MAPSIZE * Map, TOPOPIX ** TopoMap, SOILPIX ** SoilMap, AGGREGATED * Total, OPTIONSTRUCT *Options, ROADSTRUCT ** Network, SOILTABLE * SType, PRECIPPIX ** PrecipMap, SEDPIX **SedMap, float Tair, float Rh, float *SedDiams) { int x, y; int flag; char buffer[32]; float CulvertFlow; /* give any surface water to roads w/o sinks */ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SoilMap[y][x].IExcessSed = SoilMap[y][x].IExcess; if (channel_grid_has_channel(ChannelData->road_map, x, y) && !channel_grid_has_sink(ChannelData->road_map, x, y)) { /* road w/o sink */ SoilMap[y][x].RoadInt += SoilMap[y][x].IExcess; channel_grid_inc_inflow(ChannelData->road_map, x, y, SoilMap[y][x].IExcess * Map->DX * Map->DY); SoilMap[y][x].IExcess = 0.0f; } } } } if(Options->RoadRouting){ RouteRoad(Map, Time, TopoMap, SoilMap, Network, SType, ChannelData, PrecipMap, SedMap, Tair, Rh, SedDiams); } /* route the road network and save results */ SPrintDate(&(Time->Current), buffer); flag = IsEqualTime(&(Time->Current), &(Time->Start)); if (ChannelData->roads != NULL) { channel_route_network(ChannelData->roads, Time->Dt); channel_save_outflow_text(buffer, ChannelData->roads, ChannelData->roadout, ChannelData->roadflowout, flag); } /* add culvert outflow to surface water */ Total->CulvertReturnFlow = 0.0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { CulvertFlow = ChannelCulvertFlow(y, x, ChannelData); CulvertFlow /= Map->DX * Map->DY; /* CulvertFlow = (CulvertFlow > 0.0) ? CulvertFlow : 0.0; */ if (channel_grid_has_channel(ChannelData->stream_map, x, y)) { channel_grid_inc_inflow(ChannelData->stream_map, x, y, (SoilMap[y][x].IExcess + CulvertFlow) * Map->DX * Map->DY); SoilMap[y][x].ChannelInt += SoilMap[y][x].IExcess; Total->CulvertToChannel += CulvertFlow; Total->RunoffToChannel += SoilMap[y][x].IExcess; SoilMap[y][x].IExcess = 0.0f; } else { SoilMap[y][x].IExcess += CulvertFlow; Total->CulvertReturnFlow += CulvertFlow; } } } } /* route stream channels */ if (ChannelData->streams != NULL) { channel_route_network(ChannelData->streams, Time->Dt); channel_save_outflow_text(buffer, ChannelData->streams, ChannelData->streamout, ChannelData->streamflowout, flag); /* save parameters for John's RBM model */ if (Options->StreamTemp) channel_save_outflow_text_cplmt(Time, buffer,ChannelData->streams,ChannelData, flag); } }
void CheckOut(int CanopyRadAttOption, LAYER Veg, LAYER Soil, VEGTABLE *VType, SOILTABLE *SType, MAPSIZE *Map, TOPOPIX **TopoMap, VEGPIX **VegMap, SOILPIX **SoilMap) { int y, x, i, j; int *count = NULL, *scount = NULL; float a, b, l, Taud, Taub20, Taub40, Taub60, Taub80; int npixels; if (!(count = static_cast<int*>(calloc(Veg.NTypes, sizeof(int))))) { ReportError("Checkout", 1); } if (!(scount = static_cast<int *>(calloc(Soil.NTypes, sizeof(int))))) { ReportError("Checkout", 1); } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (VegMap[y][x].Veg < 1 || VegMap[y][x].Veg > Veg.NTypes) { printf("veg value %d out of range \n", VegMap[y][x].Veg); exit(-1); } count[VegMap[y][x].Veg - 1]++; if (SoilMap[y][x].Soil < 1 || SoilMap[y][x].Soil > Soil.NTypes) { printf("soil value %d out of range \n", SoilMap[y][x].Soil); exit(-1); } scount[SoilMap[y][x].Soil - 1]++; } } } i = 0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { i = i + 1; } } } printf("\nBasin has %d active pixels \n", i); npixels = i; printf("\nThe following VEG types are in the current basin \n"); for (i = 0; i < Veg.NTypes; i++) { if (count[i] > 0) printf ("Class # %d of Type: %s has fraction basin area: %5.3f\n", i + 1, VType[i].Desc, (float) count[i] / (float) npixels); VType[i].TotalDepth = 0.0; for (y = 0; y < VType[i].NSoilLayers; y++) { VType[i].TotalDepth += VType[i].RootDepth[y]; } } printf("\nThe following SOIL types are in the current basin \n"); for (i = 0; i < Soil.NTypes; i++) if (scount[i] > 0) printf ("Class # %d of Type: %s has fraction basin area: %5.3f\n", i + 1, SType[i].Desc, (float) scount[i] / (float) npixels); printf("\nSome estimates for current vegetation specification\n"); for (i = 0; i < Veg.NTypes; i++) { if (count[i] > 0) { printf("\nVegetation Type: %s\n", VType[i].Desc); printf("2meter wind speed fraction of ref level %1.3f\n", VType[i].USnow); if (VType[i].OverStory) { for (j = 0; j < 12; j++) { if (fequal(VType[i].LAIMonthly[0][j], 0.0)) { printf("Overstory LAI must be > 0\n"); exit(-1); } } /* printf("Overstory LAI July %2.3f Effective LAI July %2.3f\n", VType[i].LAIMonthly[0][6]);*/ if (CanopyRadAttOption == VARIABLE) { a = VType[i].LeafAngleA; b = VType[i].LeafAngleB; l = VType[i].LAIMonthly[0][6] / VType[i].ClumpingFactor; if (l == 0) Taud = 1.0; else Taud = exp(-b * l) * ((1 - a * l) * exp(-a * l) + (a * l) * (a * l) * evalexpint(1, a * l)); Taub20 = exp(-l * (VType[i].LeafAngleA / 0.342 + VType[i].LeafAngleB)); Taub40 = exp(-l * (VType[i].LeafAngleA / 0.642 + VType[i].LeafAngleB)); Taub60 = exp(-l * (VType[i].LeafAngleA / 0.866 + VType[i].LeafAngleB)); Taub80 = exp(-l * (VType[i].LeafAngleA / 0.984 + VType[i].LeafAngleB)); printf("Solar Altitude 20 deg Tbeam %f Tdiff %f\n", Taub20, Taud); printf("Solar Altitude 40 deg Tbeam %f Tdiff %f\n", Taub40, Taud); printf("Solar Altitude 60 deg Tbeam %f Tdiff %f\n", Taub60, Taud); printf("Solar Altitude 80 deg Tbeam %f Tdiff %f\n", Taub80, Taud); } } } } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (SoilMap[y][x].Depth <= VType[VegMap[y][x].Veg - 1].TotalDepth) { printf("Error for class %d of Type %s \n", VegMap[y][x].Veg, VType[VegMap[y][x].Veg - 1].Desc); printf("%d %d Soil depth is %f, Root depth is %f \n", y,x,SoilMap[y][x].Depth, VType[VegMap[y][x].Veg - 1].TotalDepth); exit(-1); } } } } if (count) { free(count); } if (scount) { free(scount); } }
/* ------------------------------------------------------------- ElevationSlopeAspect ------------------------------------------------------------- */ void ElevationSlopeAspect(MAPSIZE * Map, TOPOPIX ** TopoMap) { const char *Routine = "ElevationSlopeAspect"; int x; int y; int n; int k; float neighbor_elev[NNEIGHBORS]; int tempdir[NDIRS]; int steepestdirection; unsigned int sum; float min; int xn, yn; /* fill neighbor array */ for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++) { if (INBASIN(TopoMap[y][x].Mask)) { /* Count the number of cells in the basin. Need this to allocate memory for the new, smaller Elev[] and Coords[][]. */ Map->NumCells++; for (n = 0; n < NNEIGHBORS; n++) { xn = x + xneighbor[n]; yn = y + yneighbor[n]; if (valid_cell(Map, xn, yn)) { neighbor_elev[n] = ((TopoMap[yn][xn].Mask) ? TopoMap[yn][xn].Dem : (float) OUTSIDEBASIN); } else { neighbor_elev[n] = (float) OUTSIDEBASIN; } } slope_aspect(Map->DX, Map->DY, TopoMap[y][x].Dem, neighbor_elev, &(TopoMap[y][x].Slope), &(TopoMap[y][x].Aspect)); /* fill Dirs in TopoMap too */ flow_fractions(Map->DX, Map->DY, TopoMap[y][x].Slope, TopoMap[y][x].Aspect, neighbor_elev, &(TopoMap[y][x].FlowGrad), TopoMap[y][x].Dir, &(TopoMap[y][x].TotalDir)); /* Check that upslope neighbors && outsidebasin Dir = 0. */ for (n = 0; n < NDIRS; n++) tempdir[n] = 0; /* initialize */ sum = 0; for (n = 0; n < NDIRS; n++) { xn = x + xdirection[n]; yn = y + ydirection[n]; if ((TopoMap[y][x].Dir[n] > 0) && valid_cell(Map, xn, yn)) { if (!INBASIN(TopoMap[yn][xn].Mask)) { /* Can never have flow in this direction.*/ (TopoMap[y][x].TotalDir) -= TopoMap[y][x].Dir[n]; TopoMap[y][x].Dir[n] = 0; } else if(TopoMap[yn][xn].Dem >= TopoMap[y][x].Dem) { /* Will put flow in this direction if no other choice to preserve water balance. */ (TopoMap[y][x].TotalDir) -= TopoMap[y][x].Dir[n]; tempdir[n]=TopoMap[y][x].Dir[n]; TopoMap[y][x].Dir[n] = 0; } } else if((TopoMap[y][x].Dir[n] > 0) && valid_cell(Map, xn, yn)) { /* Can never have flow in this direction, should not be possible to get here. */ (TopoMap[y][x].TotalDir) -= TopoMap[y][x].Dir[n]; TopoMap[y][x].Dir[n] = 0; } sum+=TopoMap[y][x].Dir[n]; } /* If there is a sink, check again to see if there is a direction of steepest descent. Does not account for ties.*/ steepestdirection = -99; if(sum==0) { min = DHSVM_HUGE; for (n = 0; n < NDIRS; n++) { xn = x + xdirection[n]; yn = y + ydirection[n]; if (valid_cell(Map, xn, yn)) { if (INBASIN(TopoMap[yn][xn].Mask)) { if(TopoMap[yn][xn].Dem < min) { min = TopoMap[yn][xn].Dem; steepestdirection = n; }} } } if(min < TopoMap[y][x].Dem) { TopoMap[y][x].Dir[steepestdirection] = (int)(255.0 + 0.5); TopoMap[y][x].TotalDir = (int)(255.0 + 0.5); } else { /* Last resort: set the Dir of the cell to the cell that is closest in elevation. This should only happen for the basin outlet, unless the Dem wasn't filled. */ TopoMap[y][x].Dir[steepestdirection] = (int)(255.0 + 0.5); TopoMap[y][x].TotalDir = (int)(255.0 + 0.5); xn = x + xdirection[steepestdirection]; yn = y + ydirection[steepestdirection]; } } } // end if (INBASIN(TopoMap[y][x].Mask)) { } } // end of for loops /* Create a structure to hold elevations of only those cells within the basin and the y,x of those cells.*/ if (!(Map->OrderedCells = (ITEM *) calloc(Map->NumCells, sizeof(ITEM)))) ReportError((char *) Routine, 1); k = 0; for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { /* Save the elevation, y, and x in the ITEM structure. */ if (INBASIN(TopoMap[y][x].Mask)) { Map->OrderedCells[k].Rank = TopoMap[y][x].Dem; Map->OrderedCells[k].y = y; Map->OrderedCells[k].x = x; k++; } } } /* Sort Elev in descending order-- Elev.x and Elev.y hold indices. */ quick(Map->OrderedCells, Map->NumCells); /* End of modifications to create ordered cell coordinates. SRW 10/02, LCB 03/03 */ return; }
void MainMWM(SEDPIX **SedMap, FINEPIX ***FineMap, VEGTABLE *VType, SEDTABLE *SedType, CHANNEL *ChannelData, char *DumpPath, SOILPIX **SoilMap, TIMESTRUCT *Time, MAPSIZE *Map, TOPOPIX **TopoMap, SOILTABLE *SType, VEGPIX **VegMap, int MaxStreamID, SNOWPIX **SnowMap) { int x,y,xx,yy,i,j,ii,jj,k,iter; /* Counters. */ int coursei, coursej; int nextx, nexty; int prevx, prevy; int numfailedpixels; int numlikelyfailedpixels; int numfailures; float avgnumfailures; float avgpixperfailure; float failure_threshold = 0.0; char buffer[32]; char sumoutfile[100]; /* Character array to hold file name. */ int **failure; float factor_safety; float LocalSlope; FILE *fs; /* File pointer. */ int numpixels; int cells, count, checksink; int massitertemp; /* if massiter is 0, sets the counter to 1 here */ float TotalVolume; node *head, *tail; float SlopeAspect, SedimentToChannel; float *SegmentSediment; /* The cumulative sediment content over all stochastic iterations for each channel segment. */ float **SegmentSedimentm; /* The cumulative sediment mass over all stochastic iterations for each channel segment. */ float *InitialSegmentSediment; /* Placeholder of segment sediment load at beginning of time step. */ float **InitialSegmentSedimentm; /* Placeholder of segment sediment mass at beginning of time step. */ float **SedThickness; /* Cumulative sediment depth over all stochastic iterations for each pixel. */ float **InitialSediment; /* Place holder of pixel sediment load at beginning of time step. */ float SedToDownslope; /* Sediment wasted from a pixel, awaiting redistribution */ float SedFromUpslope; /* Wasted sediment being redistributed */ float FineMapTableDepth; /* Fine grid water table depth (m) */ float TableDepth; /* Coarse grid water table depth (m) */ float FineMapSatThickness; /* Fine grid saturated thickness (m) */ float **Redistribute, **TopoIndex, **TopoIndexAve; int firsti, firstj; head = NULL; tail = NULL; /***************************************************************************** Allocate memory for Soil Moisture Redistribution ****************************************************************************/ if (!(Redistribute = (float **)calloc(Map->NY, sizeof(float *)))) ReportError("MainMWM", 1); for(i=0; i<Map->NY; i++) { if (!(Redistribute[i] = (float *)calloc(Map->NX, sizeof(float)))) ReportError("MainMWM", 1); } if (!(TopoIndex = (float **)calloc(Map->NY, sizeof(float *)))) ReportError("MainMWM", 1); for(i=0; i<Map->NY; i++) { if (!(TopoIndex[i] = (float *)calloc(Map->NX, sizeof(float)))) ReportError("MainMWM", 1); } if (!(TopoIndexAve = (float **)calloc(Map->NY, sizeof(float *)))) ReportError("MainMWM", 1); for(i=0; i<Map->NY; i++) { if (!(TopoIndexAve[i] = (float *)calloc(Map->NX, sizeof(float)))) ReportError("MainMWM", 1); } /* Redistribute soil moisture from coarse grid to fine grid. The is done similarly to Burton, A. and J.C. Bathurst, 1998, Physically based modelling of shallow landslide sediment yield as a catchment scale, Environmental Geology, 35 (2-3), 89-99.*/ for (i = 0; i < Map->NY; i++) { for (j = 0; j < Map->NX; j++) { /* Check to make sure region is in the basin. */ if (INBASIN(TopoMap[i][j].Mask)) { /* Step over each fine resolution cell within the model grid cell. */ for(ii=0; ii< Map->DY/Map->DMASS; ii++) { /* Fine resolution counters. */ for(jj=0; jj< Map->DX/Map->DMASS; jj++) { y = (int) i*Map->DY/Map->DMASS + ii; x = (int) j*Map->DX/Map->DMASS + jj; TopoIndex[i][j] += (*FineMap[y][x]).TopoIndex; } } /* TopoIndexAve is the TopoIndex for the coarse grid calculated as the average of the TopoIndex of the fine grids in the coarse grid. */ TopoIndexAve[i][j] = TopoIndex[i][j]/Map->NumFineIn; } } } FineMapSatThickness = 0.; for (i = 0; i < Map->NY; i++) { for (j = 0; j < Map->NX; j++) { if (INBASIN(TopoMap[i][j].Mask)) { TableDepth = SoilMap[i][j].TableDepth; /* Do not want to distribute ponded water */ if (TableDepth < 0.) TableDepth = 0.; for(ii=0; ii< Map->DY/Map->DMASS; ii++) { for(jj=0; jj< Map->DX/Map->DMASS; jj++) { y = (int) i*Map->DY/Map->DMASS + ii; x = (int) j*Map->DX/Map->DMASS + jj; if (SoilMap[i][j].Depth > SoilMap[i][j].TableDepth){ FineMapTableDepth = TableDepth + ((TopoIndexAve[i][j]-(*FineMap[y][x]).TopoIndex)/ SType[SoilMap[i][j].Soil - 1].KsLatExp); if (FineMapTableDepth < 0.) { (*FineMap[y][x]).SatThickness = (*FineMap[y][x]).sediment; } else if (FineMapTableDepth > (*FineMap[y][x]).sediment) (*FineMap[y][x]).SatThickness = 0.; else (*FineMap[y][x]).SatThickness = (*FineMap[y][x]).sediment - FineMapTableDepth; } else (*FineMap[y][x]).SatThickness = 0.; FineMapSatThickness += (*FineMap[y][x]).SatThickness; if ((ii== Map->DY/Map->DMASS - 1) & (jj== Map->DX/Map->DMASS - 1)){ /* Calculating the difference between the volume of water distributed (only saturated) and available volume of water (m3)*/ Redistribute[i][j] = (Map->DY * Map->DX * (SoilMap[i][j].Depth - TableDepth)) - (FineMapSatThickness*Map->DMASS*Map->DMASS); FineMapSatThickness = 0.; } } } } } } /* Redistribute volume difference. Start with cells with too much water. */ for (i = 0; i < Map->NY; i++) { for (j = 0; j < Map->NX; j++) { if (INBASIN(TopoMap[i][j].Mask)) { if (Redistribute[i][j]< -25.){ for (k = 0; k < Map->NumFineIn; k++) { y = TopoMap[i][j].OrderedTopoIndex[k].y; x = TopoMap[i][j].OrderedTopoIndex[k].x; yy = TopoMap[i][j].OrderedTopoIndex[(Map->NumFineIn)-k-1].y; xx = TopoMap[i][j].OrderedTopoIndex[(Map->NumFineIn)-k-1].x; /* Convert sat thickness to a volume */ (*FineMap[y][x]).SatThickness *= (Map->DMASS)*(Map->DMASS); /* Add to volume based on amount to be redistributed */ (*FineMap[y][x]).SatThickness += Redistribute[i][j] * ((*FineMap[yy][xx]).TopoIndex/TopoIndex[i][j]); /* Convert back to thickness (m)*/ (*FineMap[y][x]).SatThickness /= (Map->DMASS)*(Map->DMASS); } } } } } /* Redistribute volume difference for cells with too little water.*/ for (i = 0; i < Map->NY; i++) { for (j = 0; j < Map->NX; j++) { if (INBASIN(TopoMap[i][j].Mask)) { for(ii=0; ii< Map->DY/Map->DMASS; ii++) { for(jj=0; jj< Map->DX/Map->DMASS; jj++) { y = (int) i*Map->DY/Map->DMASS + ii; x = (int) j*Map->DX/Map->DMASS + jj; if (Redistribute[i][j] > 25.){ /* Convert sat thickness to a volume */ (*FineMap[y][x]).SatThickness *= (Map->DMASS)*(Map->DMASS); /* Add to volume based on amount to be redistributed */ (*FineMap[y][x]).SatThickness += Redistribute[i][j] * ((*FineMap[y][x]).TopoIndex/TopoIndex[i][j]); /* Convert back to thickness (m)*/ (*FineMap[y][x]).SatThickness /= (Map->DMASS)*(Map->DMASS); } if ((Redistribute[i][j] > 25.)||(Redistribute[i][j]< -25.)){ if ((*FineMap[y][x]).SatThickness > (*FineMap[y][x]).sediment) (*FineMap[y][x]).SatThickness = (*FineMap[y][x]).sediment; else if ((*FineMap[y][x]).SatThickness < 0.) (*FineMap[y][x]).SatThickness = 0.; } } } } } } for(i=0; i<Map->NY; i++) { free(Redistribute[i]); free(TopoIndex[i]); free(TopoIndexAve[i]); } free(Redistribute); free(TopoIndex); free(TopoIndexAve); /***************************************************************************** Allocate memory for ensemble calculations *****************************************************************************/ if (!(failure = (int **)calloc(Map->NYfine, sizeof(int *)))) ReportError("MainMWM", 1); for(i=0; i<Map->NYfine; i++) { if (!(failure[i] = (int *)calloc(Map->NXfine, sizeof(int)))) ReportError("MainMWM", 1); } if (!(SedThickness = (float **)calloc(Map->NYfine, sizeof(float *)))) ReportError("MainMWM", 1); for(i=0; i<Map->NYfine; i++) { if (!(SedThickness[i] = (float *)calloc(Map->NXfine, sizeof(float)))) ReportError("MainMWM", 1); } if (!(InitialSediment = (float **)calloc(Map->NYfine, sizeof(float *)))) ReportError("MainMWM", 1); for(i=0; i<Map->NYfine; i++) { if (!(InitialSediment[i] = (float *)calloc(Map->NXfine, sizeof(float)))) ReportError("MainMWM", 1); } if (!(SegmentSediment = (float *)calloc(MaxStreamID, sizeof(float )))) ReportError("MainMWM", 1); if (!(SegmentSedimentm = (float **)calloc(MaxStreamID, sizeof(float *)))) ReportError("MainMWM", 1); for(i=1; i<MaxStreamID+1; i++) { if (!(SegmentSedimentm[i] = (float *)calloc(NSEDSIZES, sizeof(float)))) ReportError("MainMWM", 1); } if (!(InitialSegmentSediment = (float *)calloc(MaxStreamID, sizeof(float )))) ReportError("MainMWM", 1); if (!(InitialSegmentSedimentm = (float **)calloc(MaxStreamID, sizeof(float *)))) ReportError("MainMWM", 1); for(i=1; i<MaxStreamID+1; i++) { if (!(InitialSegmentSedimentm[i] = (float *)calloc(NSEDSIZES, sizeof(float)))) ReportError("MainMWM", 1); } /* Initialize arrays. */ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { for(ii=0; ii< Map->DY/Map->DMASS; ii++) { /* Fine resolution counters. */ for(jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; InitialSediment[yy][xx] = (*FineMap[yy][xx]).sediment; (*FineMap[yy][xx]).Probability = 0.; (*FineMap[yy][xx]).MassWasting = 0.; (*FineMap[yy][xx]).MassDeposition = 0.; (*FineMap[yy][xx]).SedimentToChannel = 0.; } } } } } initialize_sediment_mass(ChannelData->streams, InitialSegmentSedimentm); update_sediment_array(ChannelData->streams, InitialSegmentSediment, InitialSegmentSedimentm); /************************************************************************/ /* Begin iteration for multiple ensembles. */ /************************************************************************/ /* sloppy fix for when MASSITER=0 -- this only needs to be checked once */ if(MASSITER==0) massitertemp=1; else massitertemp=MASSITER; numfailures = 0; for(iter=0; iter < massitertemp; iter++) { printf("iter=%d\n",iter); /************************************************************************/ /* Begin factor of safety code. */ /************************************************************************/ for(i=0; i<Map->NY; i++) { for(j=0; j<Map->NX; j++) { if (INBASIN(TopoMap[i][j].Mask)) { for(ii=0; ii<Map->DY/Map->DMASS; ii++) { for(jj=0; jj<Map->DX/Map->DMASS; jj++) { y = i*Map->DY/Map->DMASS + ii; x = j*Map->DX/Map->DMASS + jj; coursei = i; coursej = j; firsti=y; firstj=x; /* Don't allow failures that will propagate outside the basin. */ /* Fine mask is optional, so they still may occur. */ if(INBASIN((*FineMap[y][x]).Mask)) { checksink = 0; numpixels = 0; SedToDownslope = 0.0; SedFromUpslope = 0.0; SedimentToChannel = 0.0; /* First check for original failure. */ if((*FineMap[y][x]).SatThickness/SoilMap[i][j].Depth > MTHRESH && failure[y][x] == 0 && (*FineMap[y][x]).sediment > 0.0) { LocalSlope = ElevationSlope(Map, TopoMap, FineMap, y, x, &nexty, &nextx, y, x, &SlopeAspect); if(LocalSlope >= 10.) { factor_safety = CalcSafetyFactor(LocalSlope, SoilMap[i][j].Soil, (*FineMap[y][x]).sediment, VegMap[i][j].Veg, SedType, VType, (*FineMap[y][x]).SatThickness, SType, SnowMap[i][j].Swq, SnowMap[i][j].Depth, iter); /* check if fine pixel fails */ if (factor_safety < FS_CRITERIA && factor_safety > 0) { numfailures++; numpixels = 1; failure[y][x] = 1; /* Update sediment depth. All sediment leaves failed fine pixel */ SedToDownslope = (*FineMap[y][x]).sediment; (*FineMap[y][x]).sediment = 0.0; // Pass sediment down to next pixel SedFromUpslope = SedToDownslope; /* Follow failures down slope; skipped if no original failure. */ while(failure[y][x] == 1 && checksink == 0 && !channel_grid_has_channel(ChannelData->stream_map, coursej, coursei) && INBASIN(TopoMap[coursei][coursej].Mask)) { /* Update counters. */ prevy = y; prevx = x; y = nexty; x = nextx; coursei = floor(y*Map->DMASS/Map->DY); coursej = floor(x*Map->DMASS/Map->DX); if (!INBASIN(TopoMap[coursei][coursej].Mask)) { printf("WARNING: attempt to propagate failure to grid cell outside basin: y %d x %d\n",y,x); printf("Depositing wasted sediment in grid cell y %d x %d\n",prevy,prevx); (*FineMap[prevy][prevx]).sediment += SedFromUpslope; SedFromUpslope = SedToDownslope = 0.0; // Since we're returning SedFromUpslope to the upslope pixel, // the upslope pixel can't be considered as part of the failure failure[prevy][prevx] = 0; } else { // Add sediment from upslope to current sediment (*FineMap[y][x]).sediment += SedFromUpslope; LocalSlope = ElevationSlope(Map, TopoMap, FineMap, y, x, &nexty, &nextx, prevy, prevx, &SlopeAspect); /* Check that not a sink */ if(LocalSlope >= 0.) { factor_safety = CalcSafetyFactor(LocalSlope, SoilMap[coursei][coursej].Soil, (*FineMap[y][x]).sediment, VegMap[coursei][coursej].Veg, SedType, VType, (*FineMap[y][x]).SatThickness, SType, SnowMap[coursei][coursej].Swq, SnowMap[coursei][coursej].Depth, iter); /* check if fine pixel fails */ if (factor_safety < FS_CRITERIA && factor_safety > 0) { numpixels += 1; failure[y][x] = 1; /* Update sediment depth. All sediment leaves failed fine pixel */ SedToDownslope = (*FineMap[y][x]).sediment; (*FineMap[y][x]).sediment = 0.0; // Pass sediment down to next pixel SedFromUpslope = SedToDownslope; } else { /* Update sediment depth. */ // Remove the sediment we added for the slope calculation // and instead prepare to distribute this sediment along runout zone (*FineMap[y][x]).sediment -= SedFromUpslope; } } /* end if(LocalSlope >= 0) { */ else { /* Update sediment depth. */ // Remove the sediment we added for the slope calculation // and instead prepare to distribute this sediment along runout zone // (*FineMap[y][x]).sediment -= SedFromUpslope; /* If it reaches here, a sink exists. A sink can not fail or run out, so move to the next pixel. */ checksink++; } } } /* End of while loop. */ if (checksink > 0) continue; /* Failure has stopped, now calculate runout distance and redistribute sediment. */ // y and x are now the coords of the first pixel of the runout // (downslope neighbor of final pixel of the failure); // this is the pixel that caused the last loop to exit, // whether due to being a sink, not failing, // being in a coarse pixel containing a stream, // or being outside the basin // If current cell is outside the basin, // stop processing this runout and go to next failure candidate if (!INBASIN(TopoMap[coursei][coursej].Mask)) { continue; } // TotalVolume = depth (not volume) being redistributed TotalVolume = SedFromUpslope; cells = 1; /* queue begins with initial unfailed pixel. */ enqueue(&head, &tail, y, x); while(LocalSlope > 4. && !channel_grid_has_channel(ChannelData->stream_map, coursej, coursei) && INBASIN(TopoMap[coursei][coursej].Mask)) { /* Redistribution stops if last pixel was a channel or was outside the basin. */ /* Update counters. */ prevy = y; prevx = x; y = nexty; x = nextx; coursei = floor(y*Map->DMASS/Map->DY); coursej = floor(x*Map->DMASS/Map->DX); if (INBASIN(TopoMap[coursei][coursej].Mask)) { LocalSlope = ElevationSlope(Map, TopoMap, FineMap, y, x, &nexty, &nextx, prevy, prevx, &SlopeAspect); enqueue(&head, &tail, y, x); cells++; } else { printf("WARNING: attempt to propagate runout to grid cell outside the basin: y %d x %d\n",y,x); printf("Final grid cell of runout will be: y %d x %d\n",prevy,prevx); } } prevy = y; prevx = x; for(count=0; count < cells; count++) { dequeue(&head, &tail, &y, &x); coursei = floor(y*Map->DMASS/Map->DY); coursej = floor(x*Map->DMASS/Map->DX); // If this node has a channel, then this MUST be the end of the queue if(channel_grid_has_channel(ChannelData->stream_map, coursej, coursei)) { /* TotalVolume at this point is a depth in m over one fine map grid cell - convert to m3 */ SedimentToChannel = TotalVolume*(Map->DMASS*Map->DMASS)/(float) cells; } else { /* Redistribute sediment equally among all hillslope cells. */ (*FineMap[y][x]).sediment += TotalVolume/cells; } } if(SedimentToChannel > 0.0) { if(SlopeAspect < 0.) { printf("Invalid aspect (%3.1f) in cell y= %d x= %d\n", SlopeAspect,y,x); exit(0); } else { // Add Current value of SedimentToChannel to running total for this FineMap cell // (allowing for more than one debris flow to end at the same channel) (*FineMap[y][x]).SedimentToChannel += SedimentToChannel; // Now route SedimentToChannel through stream network RouteDebrisFlow(&SedimentToChannel, coursei, coursej, SlopeAspect, ChannelData, Map); } } } /* End of this failure/runout event */ } } } /* End of fine mask check. */ } /* End of jj loop. */ } } } } /* End of course resolution loop. */ /* Record failures and Reset failure map for new iteration. */ for(i=0; i<Map->NY; i++) { for(j=0; j<Map->NX; j++) { if (INBASIN(TopoMap[i][j].Mask)) { for(ii=0; ii<Map->DY/Map->DMASS; ii++) { for(jj=0; jj<Map->DX/Map->DMASS; jj++) { y = i*Map->DY/Map->DMASS + ii; x = j*Map->DX/Map->DMASS + jj; (*FineMap[y][x]).Probability += (float) failure[y][x]; /* Record cumulative sediment volume. */ SedThickness[y][x] += (*FineMap[y][x]).sediment; /* Reset sediment thickness for each iteration; otherwise there is a decreasing probability of failure for subsequent iterations. */ /* If not in stochastic mode, then allow a history of past failures and do not reset sediment depth */ if(massitertemp>1) { (*FineMap[y][x]).sediment = InitialSediment[y][x]; failure[y][x] = 0; } } } } } } /* printf("Sediment Mass is "); */ /* count_sediment_mass(ChannelData->streams, InitialSegmentSediment); */ /* Record cumulative stream sediment volumes. */ initialize_sediment_array(ChannelData->streams, SegmentSediment, SegmentSedimentm); /* Reset channel sediment volume for each iteration. */ update_sediment_array(ChannelData->streams, InitialSegmentSediment, InitialSegmentSedimentm); update_sediment_mass(ChannelData->streams, SegmentSedimentm, massitertemp); } /* End iteration loop */ // Normalize mass wasting vars by number of iterations numfailedpixels = 0; numlikelyfailedpixels = 0; for(i=0; i<Map->NY; i++) { for(j=0; j<Map->NX; j++) { if (INBASIN(TopoMap[i][j].Mask)) { for(ii=0; ii<Map->DY/Map->DMASS; ii++) { for(jj=0; jj<Map->DX/Map->DMASS; jj++) { y = i*Map->DY/Map->DMASS + ii; x = j*Map->DX/Map->DMASS + jj; (*FineMap[y][x]).Probability /= (float)massitertemp; (*FineMap[y][x]).sediment = SedThickness[y][x]/(float)massitertemp; (*FineMap[y][x]).SedimentToChannel /= (float)massitertemp; if ((*FineMap[y][x]).sediment > InitialSediment[y][x]) { (*FineMap[y][x]).MassDeposition = ((*FineMap[y][x]).sediment - InitialSediment[y][x])*(Map->DMASS*Map->DMASS); (*FineMap[y][x]).MassWasting = 0.0; } else if ((*FineMap[y][x]).sediment < InitialSediment[y][x]) { (*FineMap[y][x]).MassDeposition = 0.0; (*FineMap[y][x]).MassWasting = (InitialSediment[y][x] - (*FineMap[y][x]).sediment)*(Map->DMASS*Map->DMASS); } if((*FineMap[y][x]).Probability > 0) numfailedpixels +=1; if((*FineMap[y][x]).Probability > failure_threshold) numlikelyfailedpixels +=1; (*FineMap[y][x]).DeltaDepth = (*FineMap[y][x]).sediment - SoilMap[i][j].Depth; } } } } } // Compute average number of failures avgnumfailures = numfailures/(float)massitertemp; // Compute average number of pixels per failure if (numfailures > 0) { avgpixperfailure = (float)numfailedpixels/(float)numfailures; } else { avgpixperfailure = 0.0; } // Average sediment delivery to each stream segment for(i=1; i<MaxStreamID+1; i++) { SegmentSediment[i] /= (float)massitertemp; if(SegmentSediment[i] < 0.0) SegmentSediment[i]=0.0; } update_sediment_array(ChannelData->streams, SegmentSediment, SegmentSedimentm); /* Take new sediment inflow and distribute it by representative diameters*/ /* and convert to mass */ sed_vol_to_distrib_mass(ChannelData->streams, SegmentSediment); /*************************************************************************/ /* Create failure summary file, in the specified output directory: */ /* failure_summary.txt - for each date that the mwm algorithm is run: */ /* ave. no. of failures (strip of pixels */ /* originating from a failed pixel) */ /* ave. no. of pixles per failure */ /* total number of failed pixels with probability */ /* of failure > failure_threshold */ /*************************************************************************/ sprintf(sumoutfile, "%sfailure_summary.txt", DumpPath); if((fs=fopen(sumoutfile,"a")) == NULL) { printf("Cannot open factor of safety summary output file.\n"); exit(0); } SPrintDate(&(Time->Current), buffer); fprintf(fs, "%-20s %.4f %.4f %7d\n", buffer, avgnumfailures, avgpixperfailure, numlikelyfailedpixels); printf("%.4f failures; %.4f pixels per failure; %d pixels have failure likelihood > %.2f\n", avgnumfailures, avgpixperfailure, numlikelyfailedpixels, failure_threshold); fclose(fs); for(i=0; i<Map->NYfine; i++) { free(failure[i]); free(SedThickness[i]); free(InitialSediment[i]); } for(i=1; i<MaxStreamID+1; i++) { free(SegmentSedimentm[i]); } free(failure); free(SedThickness); free(InitialSediment); free(SegmentSediment); free(SegmentSedimentm); free(InitialSegmentSediment); free(InitialSegmentSedimentm); }
/***************************************************************************** InitFineMaps() *****************************************************************************/ void InitFineMaps(LISTPTR Input, OPTIONSTRUCT *Options, MAPSIZE *Map, LAYER *Soil, TOPOPIX ***TopoMap, SOILPIX ***SoilMap, FINEPIX ****FineMap) { const char *Routine = "InitFineMaps"; char VarName[BUFSIZE+1]; /* Variable name */ int i, k, x, y; /* Counters */ int ii, jj, xx, yy, xy; /* Counters */ int NumberType; /* Number type of data set */ float *Elev; /* Surface elevation */ int MASKFLAG; unsigned char *Mask = NULL; /* Fine resolution mask */ STRINIENTRY StrEnv[] = { {"FINEDEM", "DEM FILE" , "" , ""}, {"FINEDEM", "MASK FILE" , "" , ""}, {NULL , NULL , "" , NULL} }; printf("Initializing mass wasting resolution maps\n"); /* Process the [FINEDEM] section in the input file */ /* Read the key-entry pair for the dem from the input file */ GetInitString(StrEnv[0].SectionName, StrEnv[0].KeyName, StrEnv[0].Default, StrEnv[0].VarStr, (unsigned long) BUFSIZE, Input); if (IsEmptyStr(StrEnv[0].VarStr)) ReportError(StrEnv[0].KeyName, 51); /* Read the elevation dataset */ GetVarName(001, 0, VarName); GetVarNumberType(001, &NumberType); if (!(Elev = (float *) calloc(Map->NXfine * Map->NYfine, SizeOfNumberType(NumberType)))) ReportError((char *) Routine, 1); Read2DMatrix(StrEnv[demfile].VarStr, Elev, NumberType, Map->NYfine, Map->NXfine, 0, VarName); /* Read the key-entry pair for the mask from the input file */ GetInitString(StrEnv[1].SectionName, StrEnv[1].KeyName, StrEnv[1].Default, StrEnv[1].VarStr, (unsigned long) BUFSIZE, Input); if (IsEmptyStr(StrEnv[1].VarStr)) { printf("\nWARNING: Fine resolution mask not provided, will be set equal to \n"); printf("coarse resolution mask.\n\n"); MASKFLAG = FALSE; } else { printf("fine mask = %s\n",StrEnv[1].VarStr); /* Read the mask */ GetVarName(002, 0, VarName); GetVarNumberType(002, &NumberType); if (!(Mask = (unsigned char *) calloc(Map->NXfine * Map->NYfine, SizeOfNumberType(NumberType)))) ReportError((char *) Routine, 1); Read2DMatrix(StrEnv[maskfile].VarStr, Mask, NumberType, Map->NYfine, Map->NXfine, 0, VarName); MASKFLAG = TRUE; } /* Assign the attributes to the correct map pixel */ if (!(*FineMap = (FINEPIX ***) calloc(Map->NYfine, sizeof(FINEPIX **)))) ReportError((char *) Routine, 1); for (y = 0; y < Map->NYfine; y++) { if (!((*FineMap)[y] = (FINEPIX **) calloc(Map->NXfine, sizeof(FINEPIX *)))) ReportError((char *) Routine, 1); } // Only allocate a FINEPIX structure for a fine grid cell if that grid cell // is in the coarse grid mask for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN((*TopoMap)[y][x].Mask)) { for (ii=0; ii< Map->DY/Map->DMASS; ii++) { for (jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; if (!((*FineMap)[yy][xx] = (FINEPIX *) malloc(sizeof(FINEPIX)))) { printf("error allocating FineMap[%d][%d]\n",yy,xx); ReportError((char *) Routine, 1); } } } } } } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN((*TopoMap)[y][x].Mask)) { for (ii=0; ii< Map->DY/Map->DMASS; ii++) { for (jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; xy = (int) yy*Map->NXfine + xx; (*(*FineMap)[yy][xx]).Dem = Elev[xy]; } } } } } free(Elev); if(MASKFLAG == TRUE){ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN((*TopoMap)[y][x].Mask)) { for (ii=0; ii< Map->DY/Map->DMASS; ii++) { for (jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; xy = (int) yy*Map->NXfine + xx; (*(*FineMap)[yy][xx]).Mask = Mask[xy]; } } } } } } free(Mask); /* Create fine resolution mask, sediment and bedrock maps. Initialize other variables*/ for (y = 0, i = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++, i++) { for (ii=0; ii< Map->DY/Map->DMASS; ii++) { for (jj=0; jj< Map->DX/Map->DMASS; jj++) { if (INBASIN((*TopoMap)[y][x].Mask)) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; if(MASKFLAG==FALSE) (*(*FineMap)[yy][xx]).Mask = (*TopoMap)[y][x].Mask; /* else { */ // Don't allow fine mask to extend beyond edges of coarse mask. // This means that failures may still try to leave the basin if the coarse // mask isn't wide enough because some of the drainage area may be cropped. /* if (!INBASIN((*TopoMap)[y][x].Mask)) */ /* (*(*FineMap)[yy][xx]).Mask = (*TopoMap)[y][x].Mask; */ /* } */ (*(*FineMap)[yy][xx]).bedrock = (*(*FineMap)[yy][xx]).Dem - (*SoilMap)[y][x].Depth; (*(*FineMap)[yy][xx]).sediment = (*SoilMap)[y][x].Depth; (*(*FineMap)[yy][xx]).SatThickness = 0.; (*(*FineMap)[yy][xx]).DeltaDepth = 0.; (*(*FineMap)[yy][xx]).Probability = 0.; (*(*FineMap)[yy][xx]).MassWasting = 0.; (*(*FineMap)[yy][xx]).MassDeposition = 0.; (*(*FineMap)[yy][xx]).SedimentToChannel = 0.; (*(*FineMap)[yy][xx]).TopoIndex = 0.; } } } } } Map->NumFineIn = (Map->DX/Map->DMASS) * (Map->DY/Map->DMASS); /* NumCellsfine is used in CalcTopoIndex. The topo index is calculated for every fine cell within the boundary of the coarse mask, so this number may exceed the number of pixels within the fine resolution mask. */ Map->NumCellsfine = Map->NumCells*Map->NumFineIn; printf("Basin has %d active pixels in the mass wasting resolution map\n", Map->NumCellsfine); /* Calculate the topographic index */ CalcTopoIndex(Map, *FineMap, *TopoMap); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN((*TopoMap)[y][x].Mask)) { if (!((*TopoMap)[y][x].OrderedTopoIndex = (ITEM *) calloc(Map->NumFineIn, sizeof(ITEM)))) ReportError((char *) Routine, 1); } } } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN((*TopoMap)[y][x].Mask)) { k = 0; for(ii=0; ii< Map->DY/Map->DMASS; ii++) { for(jj=0; jj< Map->DX/Map->DMASS; jj++) { yy = (int) y*Map->DY/Map->DMASS + ii; xx = (int) x*Map->DX/Map->DMASS + jj; (*TopoMap)[y][x].OrderedTopoIndex[k].Rank = (*(*FineMap)[yy][xx]).TopoIndex; (*TopoMap)[y][x].OrderedTopoIndex[k].y = yy; (*TopoMap)[y][x].OrderedTopoIndex[k].x = xx; k++; } } quick((*TopoMap)[y][x] .OrderedTopoIndex, Map->NumFineIn); } } } }
int main(int argc, char **argv) { float *Hydrograph = NULL; float ***MM5Input = NULL; float **PrecipLapseMap = NULL; float **PrismMap = NULL; unsigned char ***ShadowMap = NULL; float **SkyViewMap = NULL; float ***WindModel = NULL; int MaxStreamID, MaxRoadID; float SedDiams[NSEDSIZES]; /* Sediment particle diameters (mm) */ clock_t start, finish1; double runtime = 0.0; int t = 0; float roadarea; time_t tloc; int flag; int i; int j; int x; /* row counter */ int y; /* column counter */ int shade_offset; /* a fast way of handling arraay position given the number of mm5 input options */ int NStats; /* Number of meteorological stations */ uchar ***MetWeights = NULL; /* 3D array with weights for interpolating meteorological variables between the stations */ int NGraphics; /* number of graphics for X11 */ int *which_graphics; /* which graphics for X11 */ char buffer[32]; AGGREGATED Total = { /* Total or average value of a variable over the entire basin */ {0.0, NULL, NULL, NULL, NULL, 0.0}, /* EVAPPIX */ {0.0, 0.0, 0.0, 0.0, 0.0, NULL, NULL, 0.0, 0, 0.0}, /* PRECIPPIX */ {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, 0.0, 0.0, 0.0}, /* PIXRAD */ {0.0, 0.0}, /* RADCLASSPIX */ {0.0, 0.0, 0, NULL, NULL, 0.0, 0, 0.0, 0.0, 0.0, 0.0, NULL, NULL, NULL, NULL, NULL, NULL, 0.0}, /* ROADSTRUCT*/ {0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, /* SNOWPIX */ {0, 0.0, NULL, NULL, NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, /*SOILPIX */ { 0.0, 0.0, 0.0, 0.0, 0.0}, /*SEDPIX */ { 0.0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, /*FINEPIX */ 0.0, 0.0, 0.0, 0.0, 0.0, 0l, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; CHANNEL ChannelData = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; DUMPSTRUCT Dump; EVAPPIX **EvapMap = NULL; INPUTFILES InFiles; LAYER Soil; LAYER Veg; LISTPTR Input = NULL; /* Linked list with input strings */ MAPSIZE Map; /* Size and location of model area */ MAPSIZE Radar; /* Size and location of area covered by precipitation radar */ MAPSIZE MM5Map; /* Size and location of area covered by MM5 input files */ METLOCATION *Stat = NULL; OPTIONSTRUCT Options; /* Structure with information which program options to follow */ PIXMET LocalMet; /* Meteorological conditions for current pixel */ FINEPIX ***FineMap = NULL; PRECIPPIX **PrecipMap = NULL; RADARPIX **RadarMap = NULL; RADCLASSPIX **RadMap = NULL; PIXRAD **RadiationMap = NULL; ROADSTRUCT **Network = NULL; /* 2D Array with channel information for each pixel */ SNOWPIX **SnowMap = NULL; MET_MAP_PIX **MetMap = NULL; SNOWTABLE *SnowAlbedo = NULL; SOILPIX **SoilMap = NULL; SEDPIX **SedMap = NULL; SOILTABLE *SType = NULL; SEDTABLE *SedType = NULL; SOLARGEOMETRY SolarGeo; /* Geometry of Sun-Earth system (needed for INLINE radiation calculations */ TIMESTRUCT Time; TOPOPIX **TopoMap = NULL; UNITHYDR **UnitHydrograph = NULL; UNITHYDRINFO HydrographInfo; /* Information about unit hydrograph */ VEGPIX **VegMap = NULL; VEGTABLE *VType = NULL; WATERBALANCE Mass = /* parameter for mass balance calculations */ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; /***************************************************************************** Initialization Procedures *****************************************************************************/ if (argc != 2) { fprintf(stderr, "\nUsage: %s inputfile\n\n", argv[0]); fprintf(stderr, "DHSVM uses two output streams: \n"); fprintf(stderr, "Standard Out, for the majority of output \n"); fprintf(stderr, "Standard Error, for the final mass balance \n"); fprintf(stderr, "\nTo pipe output correctly to files: \n"); fprintf(stderr, "(cmd > f1) >& f2 \n"); fprintf(stderr, "where f1 is stdout_file and f2 is stderror_file\n"); exit(EXIT_FAILURE); } sprintf(commandline, "%s %s", argv[0], argv[1]); printf("%s \n", commandline); fprintf(stderr, "%s \n", commandline); strcpy(InFiles.Const, argv[1]); printf("\nRunning DHSVM %s\n", version); printf("\nSTARTING INITIALIZATION PROCEDURES\n\n"); /* Start recording time */ start = clock(); ReadInitFile(InFiles.Const, &Input); InitConstants(Input, &Options, &Map, &SolarGeo, &Time); InitFileIO(Options.FileFormat); InitTables(Time.NDaySteps, Input, &Options, &SType, &Soil, &VType, &Veg, &SnowAlbedo); InitTerrainMaps(Input, &Options, &Map, &Soil, &TopoMap, &SoilMap, &VegMap); CheckOut(Options.CanopyRadAtt, Veg, Soil, VType, SType, &Map, TopoMap, VegMap, SoilMap); if (Options.HasNetwork) InitChannel(Input, &Map, Time.Dt, &ChannelData, SoilMap, &MaxStreamID, &MaxRoadID, &Options); else if (Options.Extent != POINT) InitUnitHydrograph(Input, &Map, TopoMap, &UnitHydrograph, &Hydrograph, &HydrographInfo); InitNetwork(Map.NY, Map.NX, Map.DX, Map.DY, TopoMap, SoilMap, VegMap, VType, &Network, &ChannelData, Veg, &Options); InitMetSources(Input, &Options, &Map, Soil.MaxLayers, &Time, &InFiles, &NStats, &Stat, &Radar, &MM5Map); /* the following piece of code is for the UW PRISM project */ /* for real-time verification of SWE at Snotel sites */ /* Other users, set OPTION.SNOTEL to FALSE, or use TRUE with caution */ if (Options.Snotel == TRUE && Options.Outside == FALSE) { printf ("Warning: All met stations locations are being set to the vegetation class GLACIER\n"); printf ("Warning: This requires that you have such a vegetation class in your vegetation table\n"); printf("To disable this feature set Snotel OPTION to FALSE\n"); for (i = 0; i < NStats; i++) { printf("veg type for station %d is %d ", i, VegMap[Stat[i].Loc.N][Stat[i].Loc.E].Veg); for (j = 0; j < Veg.NTypes; j++) { if (VType[j].Index == GLACIER) { VegMap[Stat[i].Loc.N][Stat[i].Loc.E].Veg = j; break; } } if (j == Veg.NTypes) { /* glacier class not found */ ReportError("MainDHSVM", 62); } printf("setting to glacier type (assumed bare class): %d\n", j); } } InitMetMaps(Time.NDaySteps, &Map, &Radar, &Options, InFiles.WindMapPath, InFiles.PrecipLapseFile, &PrecipLapseMap, &PrismMap, &ShadowMap, &SkyViewMap, &EvapMap, &PrecipMap, &RadarMap, &RadMap, SoilMap, &Soil, VegMap, &Veg, TopoMap, &MM5Input, &WindModel); InitInterpolationWeights(&Map, &Options, TopoMap, &MetWeights, Stat, NStats); InitDump(Input, &Options, &Map, Soil.MaxLayers, Veg.MaxLayers, Time.Dt, TopoMap, &Dump, &NGraphics, &which_graphics); if (Options.HasNetwork == TRUE) { InitChannelDump(&Options, &ChannelData, Dump.Path); ReadChannelState(Dump.InitStatePath, &(Time.Start), ChannelData.streams); } InitSnowMap(&Map, &SnowMap); InitAggregated(Veg.MaxLayers, Soil.MaxLayers, &Total); InitModelState(&(Time.Start), &Map, &Options, PrecipMap, SnowMap, SoilMap, Soil, SType, VegMap, Veg, VType, Dump.InitStatePath, SnowAlbedo, TopoMap, Network, &HydrographInfo, Hydrograph); InitNewMonth(&Time, &Options, &Map, TopoMap, PrismMap, ShadowMap, RadMap, &InFiles, Veg.NTypes, VType, NStats, Stat, Dump.InitStatePath); InitNewDay(Time.Current.JDay, &SolarGeo); if (NGraphics > 0) { printf("Initialzing X11 display and graphics \n"); InitXGraphics(argc, argv, Map.NY, Map.NX, NGraphics, &MetMap); } shade_offset = FALSE; if (Options.Shading == TRUE) shade_offset = TRUE; /* Done with initialization, delete the list with input strings */ DeleteList(Input); /***************************************************************************** Sediment Initialization Procedures *****************************************************************************/ if(Options.Sediment) { time (&tloc); srand (tloc); /* Randomize Random Generator */ /* Commenting the line above and uncommenting the line below allows for the comparison of scenarios. */ /* srand48 (0); */ printf("\nSTARTING SEDIMENT INITIALIZATION PROCEDURES\n\n"); ReadInitFile(Options.SedFile, &Input); InitParameters(Input, &Options, &Map, &Network, &ChannelData, TopoMap, &Time, SedDiams); InitSedimentTables(Time.NDaySteps, Input, &SedType, &SType, &VType, &Soil, &Veg); InitFineMaps(Input, &Options, &Map, &Soil, &TopoMap, &SoilMap, &FineMap); if (Options.HasNetwork){ printf("Initializing channel sediment\n\n"); InitChannelSedimentDump(&ChannelData, Dump.Path, Options.ChannelRouting); InitChannelSediment(ChannelData.streams, &Total); InitChannelSediment(ChannelData.roads, &Total); } InitSedMap( &Map, &SedMap); /* Done with initialization, delete the list with input strings */ DeleteList(Input); } /* setup for mass balance calculations */ Aggregate(&Map, &Options, TopoMap, &Soil, &Veg, VegMap, EvapMap, PrecipMap, RadMap, SnowMap, SoilMap, &Total, VType, Network, SedMap, FineMap, &ChannelData, &roadarea); Mass.StartWaterStorage = Total.Soil.IExcess + Total.CanopyWater + Total.SoilWater + Total.Snow.Swq + Total.Soil.SatFlow; Mass.OldWaterStorage = Mass.StartWaterStorage; if (Options.Sediment) { Mass.StartChannelSedimentStorage = Total.ChannelSedimentStorage; Mass.LastChannelSedimentStorage = Mass.StartChannelSedimentStorage; } /* computes the number of grid cell contributing to one segment */ if (Options.StreamTemp) Init_segment_ncell(TopoMap, ChannelData.stream_map, Map.NY, Map.NX, ChannelData.streams); /***************************************************************************** Perform Calculations *****************************************************************************/ while (Before(&(Time.Current), &(Time.End)) || IsEqualTime(&(Time.Current), &(Time.End))) { ResetAggregate(&Soil, &Veg, &Total, &Options); if (IsNewMonth(&(Time.Current), Time.Dt)) InitNewMonth(&Time, &Options, &Map, TopoMap, PrismMap, ShadowMap, RadMap, &InFiles, Veg.NTypes, VType, NStats, Stat, Dump.InitStatePath); if (IsNewDay(Time.DayStep)) { InitNewDay(Time.Current.JDay, &SolarGeo); PrintDate(&(Time.Current), stdout); printf("\n"); } /* determine surface erosion and routing scheme */ SedimentFlag(&Options, &Time); InitNewStep(&InFiles, &Map, &Time, Soil.MaxLayers, &Options, NStats, Stat, InFiles.RadarFile, &Radar, RadarMap, &SolarGeo, TopoMap, RadMap, SoilMap, MM5Input, WindModel, &MM5Map); /* initialize channel/road networks for time step */ if (Options.HasNetwork) { channel_step_initialize_network(ChannelData.streams); channel_step_initialize_network(ChannelData.roads); } for (y = 0; y < Map.NY; y++) { for (x = 0; x < Map.NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (Options.Shading) LocalMet = MakeLocalMetData(y, x, &Map, Time.DayStep, &Options, NStats, Stat, MetWeights[y][x], TopoMap[y][x].Dem, &(RadMap[y][x]), &(PrecipMap[y][x]), &Radar, RadarMap, PrismMap, &(SnowMap[y][x]), SnowAlbedo, MM5Input, WindModel, PrecipLapseMap, &MetMap, NGraphics, Time.Current.Month, SkyViewMap[y][x], ShadowMap[Time.DayStep][y][x], SolarGeo.SunMax, SolarGeo.SineSolarAltitude); else LocalMet = MakeLocalMetData(y, x, &Map, Time.DayStep, &Options, NStats, Stat, MetWeights[y][x], TopoMap[y][x].Dem, &(RadMap[y][x]), &(PrecipMap[y][x]), &Radar, RadarMap, PrismMap, &(SnowMap[y][x]), SnowAlbedo, MM5Input, WindModel, PrecipLapseMap, &MetMap, NGraphics, Time.Current.Month, 0.0, 0.0, SolarGeo.SunMax, SolarGeo.SineSolarAltitude); for (i = 0; i < Soil.MaxLayers; i++) { if (Options.HeatFlux == TRUE) { if (Options.MM5 == TRUE) SoilMap[y][x].Temp[i] = MM5Input[shade_offset + i + N_MM5_MAPS][y][x]; else SoilMap[y][x].Temp[i] = Stat[0].Data.Tsoil[i]; } else SoilMap[y][x].Temp[i] = LocalMet.Tair; } MassEnergyBalance(&Options, y, x, SolarGeo.SineSolarAltitude, Map.DX, Map.DY, Time.Dt, Options.HeatFlux, Options.CanopyRadAtt, Options.RoadRouting, Options.Infiltration, Veg.MaxLayers, &LocalMet, &(Network[y][x]), &(PrecipMap[y][x]), &(VType[VegMap[y][x].Veg-1]), &(VegMap[y][x]), &(SType[SoilMap[y][x].Soil-1]), &(SoilMap[y][x]), &(SnowMap[y][x]), &(EvapMap[y][x]), &(Total.Rad), &ChannelData, SkyViewMap); PrecipMap[y][x].SumPrecip += PrecipMap[y][x].Precip; } } } /* Average all RBM inputs over each segment */ if (Options.StreamTemp) { channel_grid_avg(ChannelData.streams); } #ifndef SNOW_ONLY /* set sediment inflows to zero - they are incremented elsewhere */ if ((Options.HasNetwork) && (Options.Sediment)){ InitChannelSedInflow(ChannelData.streams); InitChannelSedInflow(ChannelData.roads); } RouteSubSurface(Time.Dt, &Map, TopoMap, VType, VegMap, Network, SType, SoilMap, &ChannelData, &Time, &Options, Dump.Path, SedMap, FineMap, SedType, MaxStreamID, SnowMap); if (Options.HasNetwork) RouteChannel(&ChannelData, &Time, &Map, TopoMap, SoilMap, &Total, &Options, Network, SType, PrecipMap, SedMap, LocalMet.Tair, LocalMet.Rh, SedDiams); /* Sediment Routing in Channel and output to sediment files */ if ((Options.HasNetwork) && (Options.Sediment)){ SPrintDate(&(Time.Current), buffer); flag = IsEqualTime(&(Time.Current), &(Time.Start)); if (Options.ChannelRouting){ if (ChannelData.roads != NULL) { RouteChannelSediment(ChannelData.roads, Time, &Dump, &Total, SedDiams); channel_save_sed_outflow_text(buffer, ChannelData.roads, ChannelData.sedroadout, ChannelData.sedroadflowout, flag); RouteCulvertSediment(&ChannelData, &Map, TopoMap, SedMap, &Total, SedDiams); } RouteChannelSediment(ChannelData.streams, Time, &Dump, &Total, SedDiams); channel_save_sed_outflow_text(buffer, ChannelData.streams, ChannelData.sedstreamout, ChannelData.sedstreamflowout, flag); } else { if (ChannelData.roads != NULL) { channel_save_sed_inflow_text(buffer, ChannelData.roads, ChannelData.sedroadinflow, SedDiams,flag); } channel_save_sed_inflow_text(buffer, ChannelData.streams, ChannelData.sedstreaminflow, SedDiams,flag); } SaveChannelSedInflow(ChannelData.roads, &Total); SaveChannelSedInflow(ChannelData.streams, &Total); } if (Options.Extent == BASIN) RouteSurface(&Map, &Time, TopoMap, SoilMap, &Options, UnitHydrograph, &HydrographInfo, Hydrograph, &Dump, VegMap, VType, SType, &ChannelData, SedMap, PrecipMap, SedType, LocalMet.Tair, LocalMet.Rh, SedDiams); #endif if (NGraphics > 0) draw(&(Time.Current), IsEqualTime(&(Time.Current), &(Time.Start)), Time.DayStep, &Map, NGraphics, which_graphics, VType, SType, SnowMap, SoilMap, SedMap, FineMap, VegMap, TopoMap, PrecipMap, PrismMap, SkyViewMap, ShadowMap, EvapMap, RadMap, MetMap, Network, &Options); Aggregate(&Map, &Options, TopoMap, &Soil, &Veg, VegMap, EvapMap, PrecipMap, RadMap, SnowMap, SoilMap, &Total, VType, Network, SedMap, FineMap, &ChannelData, &roadarea); MassBalance(&(Time.Current), &(Dump.Balance), &(Dump.SedBalance), &Total, &Mass, &Options); ExecDump(&Map, &(Time.Current), &(Time.Start), &Options, &Dump, TopoMap, EvapMap, RadiationMap, PrecipMap, RadMap, SnowMap, MetMap, VegMap, &Veg, SoilMap, SedMap, Network, &ChannelData, FineMap, &Soil, &Total, &HydrographInfo,Hydrograph); IncreaseTime(&Time); t += 1; } ExecDump(&Map, &(Time.Current), &(Time.Start), &Options, &Dump, TopoMap, EvapMap, RadiationMap, PrecipMap, RadMap, SnowMap, MetMap, VegMap, &Veg, SoilMap, SedMap, Network, &ChannelData, FineMap, &Soil, &Total, &HydrographInfo, Hydrograph); FinalMassBalance(&(Dump.FinalBalance), &Total, &Mass, &Options, roadarea); /*printf("\nSTARTING CLEANUP\n\n"); cleanup(&Dump, &ChannelData, &Options);*/ printf("\nEND OF MODEL RUN\n\n"); /* record the run time at the end of each time loop */ finish1 = clock (); runtime = (finish1-start)/CLOCKS_PER_SEC; printf("***********************************************************************************"); printf("\nRuntime Summary:\n"); printf("%6.2f hours elapsed for the simulation period of %d hours (%.1f days) \n", runtime/3600, t*Time.Dt/3600, (float)t*Time.Dt/3600/24); return EXIT_SUCCESS; }
/***************************************************************************** Function name: InitNetwork() Purpose : Initialize road/channel work. Memory is allocated, and the necessary adjustments for the soil profile are calculated Comments : *****************************************************************************/ void InitNetwork(int NY, int NX, float DX, float DY, TOPOPIX **TopoMap, SOILPIX **SoilMap, VEGPIX **VegMap, VEGTABLE *VType, ROADSTRUCT ***Network, CHANNEL *ChannelData, LAYER Veg, OPTIONSTRUCT *Options) { const char *Routine = "InitNetwork"; int i; /* counter */ int x; /* column counter */ int y; /* row counter */ int sx, sy; int minx, miny; int doimpervious; int numroads; /* Counter of number of pixels with a road and channel */ int numroadschan; /* Counter of number of pixels with a road */ FILE *inputfile; /* Allocate memory for network structure */ if (!(*Network = (ROADSTRUCT **) calloc(NY, sizeof(ROADSTRUCT *)))) ReportError((char *) Routine, 1); for (y = 0; y < NY; y++) { if (!((*Network)[y] = (ROADSTRUCT *) calloc(NX, sizeof(ROADSTRUCT)))) ReportError((char *) Routine, 1); } for (y = 0; y < NY; y++) { for (x = 0; x < NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (!((*Network)[y][x].Adjust = (float *) calloc((VType[VegMap[y][x].Veg - 1].NSoilLayers + 1), sizeof(float)))) ReportError((char *) Routine, 1); if (!((*Network)[y][x].PercArea = (float *) calloc((VType[VegMap[y][x].Veg - 1].NSoilLayers + 1), sizeof(float)))) ReportError((char *) Routine, 1); } } } numroadschan = 0; numroads = 0; /* If a road/channel Network is imposed on the area, read the Network information, and calculate the storage adjustment factors */ if (Options->HasNetwork) { for (y = 0; y < NY; y++) { for (x = 0; x < NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ChannelCut(y, x, ChannelData, &((*Network)[y][x])); AdjustStorage(VType[VegMap[y][x].Veg - 1].NSoilLayers, SoilMap[y][x].Depth, VType[VegMap[y][x].Veg - 1].RootDepth, (*Network)[y][x].Area, DX, DY, (*Network)[y][x].BankHeight, (*Network)[y][x].PercArea, (*Network)[y][x].Adjust, &((*Network)[y][x].CutBankZone)); (*Network)[y][x].IExcess = 0.; if (channel_grid_has_channel(ChannelData->road_map, x, y)) { numroads++; if (channel_grid_has_channel(ChannelData->stream_map, x, y)) { numroadschan++; } (*Network)[y][x].fraction = ChannelFraction(&(TopoMap[y][x]), ChannelData->road_map[x][y]); (*Network)[y][x].MaxInfiltrationRate = MaxRoadInfiltration(ChannelData->road_map, x, y); (*Network)[y][x].RoadClass = channel_grid_class(ChannelData->road_map, x, y); (*Network)[y][x].FlowSlope = channel_grid_flowslope(ChannelData->road_map, x, y); (*Network)[y][x].FlowLength = channel_grid_flowlength(ChannelData->road_map, x, y,(*Network)[y][x].FlowSlope); (*Network)[y][x].RoadArea = channel_grid_cell_width(ChannelData->road_map, x, y) * channel_grid_cell_length(ChannelData->road_map, x, y); } else { (*Network)[y][x].MaxInfiltrationRate = DHSVM_HUGE; (*Network)[y][x].FlowSlope = 0.; (*Network)[y][x].FlowLength = 0.; (*Network)[y][x].RoadArea = 0.; (*Network)[y][x].RoadClass = NULL; (*Network)[y][x].IExcess = 0.; } } } } } /* if no road/channel Network is imposed, set the adjustment factors to the values they have in the absence of an imposed network */ else { for (y = 0; y < NY; y++) { for (x = 0; x < NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { for (i = 0; i <= VType[VegMap[y][x].Veg - 1].NSoilLayers; i++) { (*Network)[y][x].Adjust[i] = 1.0; (*Network)[y][x].PercArea[i] = 1.0; (*Network)[y][x].CutBankZone = NO_CUT; (*Network)[y][x].MaxInfiltrationRate = 0.; } (*Network)[y][x].FlowSlope = 0.; (*Network)[y][x].FlowLength = 0.; (*Network)[y][x].RoadArea = 0.; (*Network)[y][x].RoadClass = NULL; (*Network)[y][x].IExcess = 0.; } } } } if (numroads > 0){ printf("There are %d pixels with a road and %d with a road and a channel.\n", numroads, numroadschan); } /* this all pertains to the impervious surface */ doimpervious = 0; for (i = 0; i < Veg.NTypes; i++) if (VType[i].ImpervFrac > 0.0) doimpervious = 1; if (doimpervious) { if (!(inputfile = fopen(Options->ImperviousFilePath, "rt"))) { fprintf(stderr, "User has specified a percentage impervious area \n"); fprintf(stderr, "To incorporate impervious area, DHSVM needs a file\n"); fprintf(stderr, "identified by the key: \"IMPERVIOUS SURFACE ROUTING FILE\",\n"); fprintf(stderr, "in the \"VEGETATION\" section. This file is used to \n"); fprintf(stderr, "determine the fate of surface runoff, i.e. where does it go \n"); fprintf(stderr, "This file was not found: see InitNetwork.c \n"); fprintf(stderr, "The code find_nearest_channel.c will make the file\n"); ReportError(Options->ImperviousFilePath, 3); } for (y = 0; y < NY; y++) { for (x = 0; x < NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (fscanf(inputfile, "%d %d %d %d \n", &sy, &sx, &miny, &minx) != EOF) { TopoMap[y][x].drains_x = minx; TopoMap[y][x].drains_y = miny; } else { ReportError(Options->ImperviousFilePath, 63); } if (sx != x || sy != y) { ReportError(Options->ImperviousFilePath, 64); } if (!channel_grid_has_channel(ChannelData->stream_map, minx, miny)) { printf("Routing file is wrong. The desitination cell is no channel cell!\n"); exit(0); } } } } } }
/***************************************************************************** StoreModelState() Store the current state of the model. The state variables for DHSVM include the following variables: - Canopy interception for each vegetation layer - Snow pack conditions: - presence/absence - number of days since last snowfall (used in albedo calculation) - snow water equivalent - for each layer of the snow pack: - liquid water content - temperature - cold content - Soil conditions: - for each soil layer: - soil moisture (also for the layer below the deepest root zone) - temperature - surface temperature - ground heat storage *****************************************************************************/ void StoreModelState(char *Path, DATE * Current, MAPSIZE * Map, OPTIONSTRUCT * Options, TOPOPIX ** TopoMap, PRECIPPIX ** PrecipMap, SNOWPIX ** SnowMap, MET_MAP_PIX ** MetMap, RADCLASSPIX ** RadMap, VEGCHEMPIX ** VegChemMap, LAYER * Veg, SOILPIX ** SoilMap, LAYER * Soil, UNITHYDRINFO * HydrographInfo, float *Hydrograph) { const char *Routine = "StoreModelState"; char Str[NAMESIZE + 1]; char FileLabel[MAXSTRING + 1]; char FileName[NAMESIZE + 1]; FILE *HydroStateFile; int i; /* counter */ int x; /* counter */ int y; /* counter */ int NSoil; /* Number of soil layers for current pixel */ int NVeg; /* Number of veg layers for current pixel */ MAPDUMP DMap; /* Dump Info */ void *Array; /* print a message to stdout that state is being stored */ printf("Saving Model State at: "); PrintDate(Current, stdout); printf("\n"); /* Only save met state during debug, it is not needed for start-up */ if (MetMap != NULL && DEBUG) { sprintf(Str, "%02d.%02d.%04d.%02d.%02d.%02d", Current->Month, Current->Day, Current->Year, Current->Hour, Current->Min, Current->Sec); sprintf(FileName, "%sMet.State.%s%s", Path, Str, fileext); strcpy(FileLabel, "Basic Meteorology at time step"); CreateMapFile(FileName, FileLabel, Map); if (!(Array = (float *) calloc(Map->NY * Map->NX, sizeof(float)))) ReportError((char *) Routine, 1); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = PrecipMap[y][x].Precip; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 201; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = MetMap[y][x].accum_precip; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 701; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = MetMap[y][x].air_temp; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 702; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = MetMap[y][x].wind_speed; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 703; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = MetMap[y][x].humidity; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 704; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = RadMap[y][x].Beam + RadMap[y][x].Diffuse; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 303; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); free(Array); } /* Store the canopy interception */ sprintf(Str, "%02d.%02d.%04d.%02d.%02d.%02d", Current->Month, Current->Day, Current->Year, Current->Hour, Current->Min, Current->Sec); printf("Writing %sInterception.State.%s%s...\n", Path, Str, fileext); sprintf(FileName, "%sInterception.State.%s%s", Path, Str, fileext); strcpy(FileLabel, "Interception storage for each vegetation layer"); CreateMapFile(FileName, FileLabel, Map); if (!(Array = (float *) calloc(Map->NY * Map->NX, sizeof(float)))) ReportError((char *) Routine, 1); for (i = 0; i < Veg->MaxLayers; i++) { for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NVeg = Veg->NLayers[(VegChemMap[y][x].Veg - 1)]; if (i < NVeg) ((float *) Array)[y * Map->NX + x] = PrecipMap[y][x].IntRain[i]; else ((float *) Array)[y * Map->NX + x] = NA; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 202; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); } for (i = 0; i < Veg->MaxLayers; i++) { for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { NVeg = Veg->NLayers[(VegChemMap[y][x].Veg - 1)]; if (i < NVeg) ((float *) Array)[y * Map->NX + x] = PrecipMap[y][x].IntSnow[i]; else ((float *) Array)[y * Map->NX + x] = NA; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 203; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { ((float *) Array)[y * Map->NX + x] = PrecipMap[y][x].TempIntStorage; } else { ((float *) Array)[y * Map->NX + x] = NA; } } } DMap.ID = 204; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); free(Array); /* Store the snow pack conditions */ printf("Writing %sSnow.State.%s%s...\n", Path, Str, fileext); sprintf(FileName, "%sSnow.State.%s%s", Path, Str, fileext); strcpy(FileLabel, "Snow pack moisture and temperature state"); CreateMapFile(FileName, FileLabel, Map); if (!(Array = (float *) calloc(Map->NY * Map->NX, sizeof(float)))) ReportError((char *) Routine, 1); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = (float) SnowMap[y][x].HasSnow; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 401; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = (float) SnowMap[y][x].LastSnow; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 403; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SnowMap[y][x].Swq; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 404; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SnowMap[y][x].PackWater; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 406; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SnowMap[y][x].TPack; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 407; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SnowMap[y][x].SurfWater; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 408; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SnowMap[y][x].TSurf; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 409; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SnowMap[y][x].ColdContent; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 410; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); free(Array); /* Store the soil conditions */ printf("Writing %sSoil.State.%s%s...\n", Path, Str, fileext); sprintf(FileName, "%sSoil.State.%s%s", Path, Str, fileext); strcpy(FileLabel, "Soil moisture and temperature state"); CreateMapFile(FileName, FileLabel, Map); if (!(Array = (float *) calloc(Map->NY * Map->NX, sizeof(float)))) ReportError((char *) Routine, 1); for (i = 0; i < Soil->MaxLayers + 1; 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) ((float *) Array)[y * Map->NX + x] = SoilMap[y][x].Moist_m_m[i]; else ((float *) Array)[y * Map->NX + x] = NA; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 501; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SoilMap[y][x].TSurf; else ((float *) Array)[y * Map->NX + x] = SoilMap[y][x].TSurf; } } DMap.ID = 505; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (i = 0; i < Soil->MaxLayers; 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) ((float *) Array)[y * Map->NX + x] = SoilMap[y][x].Temp[i]; else ((float *) Array)[y * Map->NX + x] = NA; } else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 511; DMap.Layer = i; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); } for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SoilMap[y][x].Qst; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 510; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) ((float *) Array)[y * Map->NX + x] = SoilMap[y][x].Runoff_m; else ((float *) Array)[y * Map->NX + x] = NA; } } DMap.ID = 512; DMap.Resolution = MAP_OUTPUT; strcpy(DMap.FileName, ""); GetVarAttr(&DMap); Write2DMatrix(FileName, Array, DMap.NumberType, Map->NY, Map->NX, &DMap, 0); free(Array); /* If the unit hydrograph is used for flow routing, store the unit hydrograph array */ if (Options->Extent == BASIN && Options->HasNetwork == FALSE) { sprintf(FileName, "%sHydrograph.State.%s", Path, Str); OpenFile(&HydroStateFile, FileName, "w", FALSE); for (i = 0; i < HydrographInfo->TotalWaveLength; i++) fprintf(HydroStateFile, "%f\n", Hydrograph[i]); fclose(HydroStateFile); } }
/******************************************************************************* Function name: InitGridMet() Purpose : Read the gridded met file. This information is in the [METEOROLOGY] section *****************************************************************************/ void InitGridMet(OPTIONSTRUCT *Options, LISTPTR Input, MAPSIZE *Map, TOPOPIX **TopoMap, GRID *Grid, METLOCATION **Stat, int *NStats) { char *Routine = "InitGridMet"; char KeyName[BUFSIZE + 1]; char VarStr[BUFSIZE + 1]; int i, j, k, m; float lat, lon, North, East; STRINIENTRY StrEnv[] = { { "METEOROLOGY", "GRID ROWS", "", "" }, { "METEOROLOGY", "GRID COLS", "", "" }, { "METEOROLOGY", "EXTREME NORTH LAT", "", "" }, { "METEOROLOGY", "EXTREME EAST LON", "", "" }, { "METEOROLOGY", "GRID SIZE", "", "" }, { "METEOROLOGY", "MET FILE PATH", "", "" }, { NULL, NULL, "", NULL }, }; /* Allocate memory for the stations */ if (!(Grid = (GRID *) calloc(1, sizeof(GRID)))) ReportError(Routine, 1); /* 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); if (!CopyFloat(&(Grid->LatOrig), StrEnv[grid_ext_north].VarStr, 1)) ReportError(StrEnv[grid_ext_north].KeyName, 51); if (!CopyFloat(&(Grid->LonOrig), StrEnv[grid_ext_east].VarStr, 1)) ReportError(StrEnv[grid_ext_east].KeyName, 51); if (!CopyInt(&(Grid->row), StrEnv[grid_rows].VarStr, 1)) ReportError(StrEnv[grid_rows].KeyName, 51); if (!CopyInt(&(Grid->col), StrEnv[grid_cols].VarStr, 1)) ReportError(StrEnv[grid_cols].KeyName, 51); /* total number of grid cell */ *NStats = Grid->row * Grid->col; if (!CopyFloat(&(Grid->GridSize), StrEnv[grid_size].VarStr, 1)) ReportError(StrEnv[grid_size].KeyName, 51); /* path to all grid met files */ if (IsEmptyStr(StrEnv[grid_met_file].VarStr)) ReportError(StrEnv[grid_met_file].KeyName, 51); strcpy(Grid->filepath, StrEnv[grid_met_file].VarStr); /* Allocate memory for the stations */ if (!(*Stat = (METLOCATION *)calloc(*NStats, sizeof(METLOCATION)))) ReportError(Routine, 1); k = 0; m = 0; for (i = 0; i < Grid->col; i++) { for (j = 0; j < Grid->row; j++) { lon = Grid->LonOrig - Grid->GridSize * i; lat = Grid->LatOrig - Grid->GridSize * j; /* convert lat and lon to utm */ deg2utm(lat, lon, &East, &North); (*Stat)[k].Loc.N = Round(((Map->Yorig - 0.5 * Map->DY) - North) / Map->DY); (*Stat)[k].Loc.E = Round((East - (Map->Xorig + 0.5 * Map->DX)) / Map->DX); sprintf((*Stat)[k].Name, "data_%.5f_%.5f", lat, lon); m += 1; if (((*Stat)[k].Loc.N >= Map->NY || (*Stat)[k].Loc.N < 0 || (*Stat)[k].Loc.E >= Map->NX || (*Stat)[k].Loc.E < 0) ) printf("Station %d outside the basin: %s ignored\n", m + 1, (*Stat)[k].Name); else { if (INBASIN(TopoMap[(*Stat)[k].Loc.N][(*Stat)[k].Loc.E].Mask)) { /* open met data file */ sprintf((*Stat)[k].MetFile.FileName, "%s%.5f_%.5f", Grid->filepath, lat, lon); if (!((*Stat)[k].MetFile.FilePtr = fopen((*Stat)[k].MetFile.FileName, "r"))) { printf("%s doesn't exist\n", (*Stat)[k].MetFile.FileName); continue; } k = k + 1; } } } } /* if no grid is found within the mask, exit with error */ if (k < 1) ReportError(Routine, 69); if (Options->Outside == FALSE) printf("Final number of stations in bounding box is %d \n\n", k); else printf("Forced to include all %d stations \n", k); *NStats = k; }
void main_spinup(MAPSIZE *Map, TOPOPIX **TopoMap, SNOWPIX **Snow, GLPIX **GlacierMap, double dt_year, double year_min, double year_max,DATE *Current, DUMPSTRUCT *Dump, OPTIONSTRUCT * Options) { FILE *f_out1 ; double *b, *s_init, *s_out, *b_dot; double dt_yr; double yr_min; double yr_max; float gl_cov; float h_max; int k; int x; int y; char file_out1[80]; float *Array1; int n_mask; /* Use Glen parameter with Annual units */ double A_GLEN = 7.5738e-17; // 7.5738e-17 Cuffey & Paterson (4th ed) Glen's law parameter in Pa^{-3} yr^{-1} units (same as A_GLEN=2.4e-24 Pa^{-3} s^{-1}) extern double RHO; extern double n_GLEN; extern double C_SLIDE; extern double m_SLIDE; extern double A_tilde; extern double C_tilde; extern double g; extern double dx; extern int N; extern double nm_half; extern double np1; extern double mm_half; extern double m1; // h = malloc(N*sizeof(double)); // ice thickness (vectorized) b = malloc(N*sizeof(double)); // bed surface elevation (vectorized) s_init = malloc(N*sizeof(double)); // initial ice surface elevation (vectorized) s_out = malloc(N*sizeof(double)); // output ice surface elevation (vectorized) b_dot = malloc(N*sizeof(double)); // Array = malloc(N*sizeof(float)); // if (!(Array1 = (float *) calloc(Map->NX * Map->NY, sizeof(float)))); dt_yr = dt_year; yr_min = year_min; yr_max = year_max; k = 0; nm_half = (n_GLEN-1)/2; np1 = n_GLEN+1; mm_half = (m_SLIDE-1)/2; m1 = m_SLIDE; n_mask = 0; gl_cov = 0; h_max = 0; // printf("dt_yr= %f yr_min= %f yr_max= %f", dt_yr, yr_min, yr_max);ic_jp[k] = ny*ic[i] + jp[j];for (i=0; i<nx; i++) for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++) { k = x*Map->NY + y; if (INBASIN(TopoMap[y][x].Mask)){ b_dot[k] = GlacierMap[y][x].Mbal; b[k] = GlacierMap[y][x].b; s_init[k]= b[k]; n_mask +=1; } else { /*The following line forces mass balance to be very negative outside of glacier mask*/ //b_dot[k] = -20; b[k] = GlacierMap[y][x].b; s_init[k] = b[k]; } } } A_tilde = 2*A_GLEN*pow(RHO*g,n_GLEN)/((n_GLEN+2)*pow(dx,2)); C_tilde = C_SLIDE*pow(RHO*g,m_SLIDE)/pow(dx,2); SetupIndexArrays(); RunGlacier(b, s_init, s_out, yr_min, yr_max, dt_yr, b_dot, Options); gl_cov = 0; h_max = 0; for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++) { if (INBASIN(TopoMap[y][x].Mask)){ k = x*Map->NY + y; GlacierMap[y][x].s_init = s_out[k]; GlacierMap[y][x].s_out = s_out[k]; GlacierMap[y][x].h = GlacierMap[y][x].s_out - GlacierMap[y][x].b; Snow[y][x].Iwq = GlacierMap[y][x].h * (900./1000.); Snow[y][x].iweold = Snow[y][x].Iwq; GlacierMap[y][x].totmbal = 0.0; if( GlacierMap[y][x].s_out<=GlacierMap[y][x].b) GlacierMap[y][x].s_out = GlacierMap[y][x].b; else { if (GlacierMap[y][x].s_out- GlacierMap[y][x].b > h_max) h_max = GlacierMap[y][x].s_out - GlacierMap[y][x].b; } if (GlacierMap[y][x].s_out > GlacierMap[y][x].b) gl_cov += 1; } //else{ //b_dot[k] = -20; //b[k] = GlacierMap[y][x].b; //s_init[k] = b[k]; // } } } sprintf(file_out1, "%sh_spinup.bin", Dump->Path); if((f_out1=fopen(file_out1,"wb"))==NULL) { printf("main(): Cannot open output file %s\n", file_out1); exit(1); } for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++){ k = x*Map->NY + y; //((float *) Array)[y * Map->NX + x] = b_dot[k]; ((float *) Array1)[y * Map->NX + x] = GlacierMap[y][x].h; } } fwrite(Array1, sizeof(Array1), Map->NY * Map->NX, f_out1); free(Array1); free(b); free(s_out); free(s_init); free(b_dot); fclose(f_out1); printf("ALL DONE: %.2f yr integration\n", yr_max); }
/***************************************************************************** InitSoilMap() *****************************************************************************/ void InitSoilMap(LISTPTR Input, OPTIONSTRUCT * Options, MAPSIZE * Map, LAYER * Soil, TOPOPIX ** TopoMap, SOILPIX *** SoilMap) { const char *Routine = "InitSoilMap"; char VarName[BUFSIZE + 1]; /* Variable name */ int i; /* counter */ int x; /* counter */ int y; /* counter */ int NumberType; /* number type */ unsigned char *Type; /* Soil type */ float *Depth; /* Soil depth */ int flag; STRINIENTRY StrEnv[] = { {"SOILS", "SOIL MAP FILE", "", ""}, {"SOILS", "SOIL DEPTH FILE", "", ""}, {NULL, NULL, "", NULL} }; /* Process the filenames in the [SOILS] section in the input file */ /* Assign the attributes to the correct map pixel */ if (!(*SoilMap = (SOILPIX **) calloc(Map->NY, sizeof(SOILPIX *)))) ReportError((char *) Routine, 1); for (y = 0; y < Map->NY; y++) { if (!((*SoilMap)[y] = (SOILPIX *) calloc(Map->NX, sizeof(SOILPIX)))) ReportError((char *) Routine, 1); } /* 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); if (IsEmptyStr(StrEnv[i].VarStr)) ReportError(StrEnv[i].KeyName, 51); } /* Read the soil type */ GetVarName(003, 0, VarName); GetVarNumberType(003, &NumberType); if (!(Type = (unsigned char *) calloc(Map->NX * Map->NY, SizeOfNumberType(NumberType)))) ReportError((char *) Routine, 1); flag = Read2DMatrix(StrEnv[soiltype_file].VarStr, Type, NumberType, Map->NY, Map->NX, 0, VarName, 0); if ((Options->FileFormat == NETCDF && flag == 0) || (Options->FileFormat == BIN)) { for (y = 0, i = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++, i++) { if (((int) Type[i]) > Soil->NTypes) ReportError(StrEnv[soiltype_file].VarStr, 32); (*SoilMap)[y][x].Soil = Type[i]; } } } else if (Options->FileFormat == NETCDF && flag == 1){ for (y = Map->NY - 1, i = 0; y >= 0; y--) { for (x = 0; x < Map->NX; x++, i++) { if (((int) Type[i]) > Soil->NTypes) ReportError(StrEnv[soiltype_file].VarStr, 32); (*SoilMap)[y][x].Soil = Type[i]; } } } else ReportError((char *) Routine, 57); /* Read the total soil depth */ GetVarName(004, 0, VarName); GetVarNumberType(004, &NumberType); if (!(Depth = (float *) calloc(Map->NX * Map->NY, SizeOfNumberType(NumberType)))) ReportError((char *) Routine, 1); flag = Read2DMatrix(StrEnv[soildepth_file].VarStr, Depth, NumberType, Map->NY, Map->NX, 0, VarName, 0); /* Assign the attributes to the correct map pixel */ if ((Options->FileFormat == NETCDF && flag == 0) || (Options->FileFormat == BIN)) { for (y = 0, i = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++, i++) { (*SoilMap)[y][x].Depth = Depth[i]; } } } else if (Options->FileFormat == NETCDF && flag == 1){ for (y = Map->NY - 1, i = 0; y >= 0; y--) { for (x = 0; x < Map->NX; x++, i++) { (*SoilMap)[y][x].Depth = Depth[i]; } } } else ReportError((char *) Routine, 57); for (y = 0, i = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++, i++) { if (Options->Infiltration == DYNAMIC) (*SoilMap)[y][x].InfiltAcc = 0.; (*SoilMap)[y][x].MoistInit = 0.; /* allocate memory for the number of root layers, plus an additional layer below the deepest root layer */ if (INBASIN(TopoMap[y][x].Mask)) { if (!((*SoilMap)[y][x].Moist = (float *) calloc((Soil->NLayers[Type[i] - 1] + 1), sizeof(float)))) ReportError((char *) Routine, 1); if (!((*SoilMap)[y][x].Perc = (float *) calloc(Soil->NLayers[Type[i] - 1], sizeof(float)))) ReportError((char *) Routine, 1); if (!((*SoilMap)[y][x].Temp = (float *) calloc(Soil->NLayers[Type[i] - 1], sizeof(float)))) ReportError((char *) Routine, 1); } else { (*SoilMap)[y][x].Moist = NULL; (*SoilMap)[y][x].Perc = NULL; (*SoilMap)[y][x].Temp = NULL; } } } free(Type); free(Depth); }
int main(int argc, char **argv) { float *Hydrograph = NULL; float ***MM5Input = NULL; float **PrecipLapseMap = NULL; float **PrismMap = NULL; unsigned char ***ShadowMap = NULL; float **SkyViewMap = NULL; float ***WindModel = NULL; /* Glacier Model Variable */ double dt_year; double year_min; double year_max; int MaxStreamID, MaxRoadID; clock_t start, finish1; double runtime = 0.0; int t = 0; float roadarea; int i; int j; int x; /* row counter */ int y; /* column counter */ int shade_offset; /* a fast way of handling arraay position given the number of mm5 input options */ int NStats; /* Number of meteorological stations */ uchar ***MetWeights = NULL; /* 3D array with weights for interpolating meteorological variables between the stations */ int NGraphics; /* number of graphics for X11 */ int *which_graphics; /* which graphics for X11 */ AGGREGATED Total = { /* Total or average value of a variable over the entire basin */ {0.0, NULL, NULL, NULL, NULL, 0.0}, /* EVAPPIX */ {0.0, 0.0, 0.0, 0.0, 0.0, NULL, NULL, 0.0, 0, 0.0}, /* PRECIPPIX */ {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, 0.0, {0.0, 0.0}, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, /* PIXRAD */ {0.0, 0.0, 0, NULL, NULL, 0.0, 0, 0.0, 0.0, 0.0, 0.0, NULL, NULL}, /* ROADSTRUCT*/ {0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, /* SNOWPIX */ {0, 0.0, NULL, NULL, NULL, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, /* SOILPIX */ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0l, 0.0, 0.0 }; CHANNEL ChannelData = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; DUMPSTRUCT Dump; EVAPPIX **EvapMap = NULL; INPUTFILES InFiles; LAYER Soil; LAYER Veg; LISTPTR Input = NULL; /* Linked list with input strings */ MAPSIZE Map; /* Size and location of model area */ MAPSIZE Radar; /* Size and location of area covered by precipitation radar */ MAPSIZE MM5Map; /* Size and location of area covered by MM5 input files */ GRID Grid; METLOCATION *Stat = NULL; OPTIONSTRUCT Options; /* Structure with information which program options to follow */ PIXMET LocalMet; /* Meteorological conditions for current pixel */ PRECIPPIX **PrecipMap = NULL; RADARPIX **RadarMap = NULL; PIXRAD **RadiationMap = NULL; ROADSTRUCT **Network = NULL; /* 2D Array with channel information for each pixel */ SNOWPIX **SnowMap = NULL; GLPIX **GlacierMap = NULL; /* glacier model*/ MET_MAP_PIX **MetMap = NULL; SNOWTABLE *SnowAlbedo = NULL; SOILPIX **SoilMap = NULL; SOILTABLE *SType = NULL; SOLARGEOMETRY SolarGeo; /* Geometry of Sun-Earth system (needed for INLINE radiation calculations */ TIMESTRUCT Time; TOPOPIX **TopoMap = NULL; UNITHYDR **UnitHydrograph = NULL; UNITHYDRINFO HydrographInfo; /* Information about unit hydrograph */ VEGPIX **VegMap = NULL; VEGTABLE *VType = NULL; WATERBALANCE Mass = /* parameter for mass balance calculations */ { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; /***************************************************************************** Initialization Procedures *****************************************************************************/ if (argc != 2) { fprintf(stderr, "\nUsage: %s inputfile\n\n", argv[0]); fprintf(stderr, "DHSVM uses two output streams: \n"); fprintf(stderr, "Standard Out, for the majority of output \n"); fprintf(stderr, "Standard Error, for the final mass balance \n"); fprintf(stderr, "\nTo pipe output correctly to files: \n"); fprintf(stderr, "(cmd > f1) >& f2 \n"); fprintf(stderr, "where f1 is stdout_file and f2 is stderror_file\n"); exit(EXIT_FAILURE); } sprintf(commandline, "%s %s", argv[0], argv[1]); printf("%s \n", commandline); fprintf(stderr, "%s \n", commandline); strcpy(InFiles.Const, argv[1]); printf("\nRunning DHSVM %s\n", version); printf("\nSTARTING INITIALIZATION PROCEDURES\n\n"); /* Start recording time */ start = clock(); ReadInitFile(InFiles.Const, &Input); InitConstants(Input, &Options, &Map, &SolarGeo, &Time); InitFileIO(Options.FileFormat); InitTables(Time.NDaySteps, Input, &Options, &SType, &Soil, &VType, &Veg, &SnowAlbedo); InitGlacierMap(&Map, &GlacierMap); /*glacier model*/ InitTerrainMaps(Input, &Options, &Map, &Soil, &TopoMap, &SoilMap, &VegMap, &GlacierMap); CheckOut(&Options, Veg, Soil, VType, SType, &Map, TopoMap, VegMap, SoilMap); if (Options.HasNetwork) InitChannel(Input, &Map, Time.Dt, &ChannelData, SoilMap, &MaxStreamID, &MaxRoadID, &Options); else if (Options.Extent != POINT) InitUnitHydrograph(Input, &Map, TopoMap, &UnitHydrograph, &Hydrograph, &HydrographInfo); InitNetwork(Map.NY, Map.NX, Map.DX, Map.DY, TopoMap, SoilMap, VegMap, VType, &Network, &ChannelData, Veg, &Options); InitMetSources(Input, &Options, &Map, TopoMap, Soil.MaxLayers, &Time, &InFiles, &NStats, &Stat, &Radar, &MM5Map, &Grid); /* the following piece of code is for the UW PRISM project */ /* for real-time verification of SWE at Snotel sites */ /* Other users, set OPTION.SNOTEL to FALSE, or use TRUE with caution */ if (Options.Snotel == TRUE && Options.Outside == FALSE) { printf ("Warning: All met stations locations are being set to the vegetation class GLACIER\n"); printf ("Warning: This requires that you have such a vegetation class in your vegetation table\n"); printf("To disable this feature set Snotel OPTION to FALSE\n"); for (i = 0; i < NStats; i++) { printf("veg type for station %d is %d ", i, VegMap[Stat[i].Loc.N][Stat[i].Loc.E].Veg); for (j = 0; j < Veg.NTypes; j++) { if (VType[j].Index == GLACIER) { VegMap[Stat[i].Loc.N][Stat[i].Loc.E].Veg = j; break; } } if (j == Veg.NTypes) { /* glacier class not found */ ReportError("MainDHSVM", 62); } printf("setting to glacier type (assumed bare class): %d\n", j); } } InitMetMaps(Time.NDaySteps, &Map, &Radar, &Options, InFiles.WindMapPath, InFiles.PrecipLapseFile, &PrecipLapseMap, &PrismMap, &ShadowMap, &SkyViewMap, &EvapMap, &PrecipMap, &RadarMap, &RadiationMap, SoilMap, &Soil, VegMap, &Veg, TopoMap, &MM5Input, &WindModel); InitInterpolationWeights(&Map, &Options, TopoMap, &MetWeights, Stat, NStats); InitDump(Input, &Options, &Map, Soil.MaxLayers, Veg.MaxLayers, Time.Dt, TopoMap, &Dump, &NGraphics, &which_graphics); if (Options.HasNetwork == TRUE) { InitChannelDump(&Options, &ChannelData, Dump.Path); ReadChannelState(Dump.InitStatePath, &(Time.Start), ChannelData.streams); if (Options.StreamTemp && Options.CanopyShading) InitChannelRVeg(&Time, ChannelData.streams); } InitSnowMap(&Map, &SnowMap); InitAggregated(Veg.MaxLayers, Soil.MaxLayers, &Total); InitModelState(&(Time.Start), &Map, &Options, PrecipMap, SnowMap, SoilMap, Soil, SType, VegMap, Veg, VType, Dump.InitStatePath, SnowAlbedo, TopoMap, Network, &HydrographInfo, Hydrograph, &Total, GlacierMap); #ifdef HAVE_GLACIER /* Glacier Model is run independently to "spinup" glacier ice state over 1000 years */ if (Options.Glacier == GLSPINUP){ dt_year = 1; year_min = 0; year_max = 1000; printf("Glacier model spin up run for %f years\n", year_max); main_spinup(&Map, TopoMap, SnowMap,GlacierMap, dt_year,year_min,year_max, &(Time.Current), &Dump, &Options); return EXIT_SUCCESS; } #endif InitNewMonth(&Time, &Options, &Map, TopoMap, PrismMap, ShadowMap, &InFiles, Veg.NTypes, VType, NStats, Stat, Dump.InitStatePath); InitNewDay(Time.Current.JDay, &SolarGeo); if (NGraphics > 0) { printf("Initialzing X11 display and graphics \n"); InitXGraphics(argc, argv, Map.NY, Map.NX, NGraphics, &MetMap); } shade_offset = FALSE; if (Options.Shading == TRUE) shade_offset = TRUE; /* Done with initialization, delete the list with input strings */ DeleteList(Input); /* setup for mass balance calculations */ Aggregate(&Map, &Options, TopoMap, &Soil, &Veg, VegMap, EvapMap, PrecipMap, RadiationMap, SnowMap, SoilMap, &Total, VType, Network, &ChannelData, &roadarea); Mass.StartWaterStorage = Total.Soil.IExcess + Total.CanopyWater + Total.SoilWater + Total.Snow.Swq + Total.Soil.SatFlow + Total.Snow.Iwq + Total.Snow.IceRemoved; Mass.OldWaterStorage = Mass.StartWaterStorage; /* computes the number of grid cell contributing to one segment */ if (Options.StreamTemp) Init_segment_ncell(TopoMap, ChannelData.stream_map, Map.NY, Map.NX, ChannelData.streams); /***************************************************************************** Perform Calculations *****************************************************************************/ while (Before(&(Time.Current), &(Time.End)) || IsEqualTime(&(Time.Current), &(Time.End))) { /* debug */ if (Time.Current.Month == 5 && Time.Current.Day == 20 && Time.Current.Hour >= 9 && Time.Current.Hour <= 15) printf("stop here for a little\n"); /* debug ends */ /* reset aggregated variables */ ResetAggregate(&Soil, &Veg, &Total, &Options); if (IsNewMonth(&(Time.Current), Time.Dt)){ InitNewMonth(&Time, &Options, &Map, TopoMap, PrismMap, ShadowMap, &InFiles, Veg.NTypes, VType, NStats, Stat, Dump.InitStatePath); #ifdef HAVE_GLACIER /* Run the glacier model at the end of every month */ if (Options.Glacier == GLSTATIC || Options.Glacier == GLDYNAMIC){ dt_year = 1.0; year_min = 1.0; year_max = 1.0; if(Time.Current.Month == 10 && Time.Current.Day == 1){ /* Calculate Equilibrium Line Altitude at end of Water Year (assumed Oct1) */ /* will need to be changed depending on geography define water year */ calc_ela(&Map, TopoMap,SnowMap,GlacierMap,&(Time.Current), &Dump); } main_gl(&Map, TopoMap, SnowMap,GlacierMap, dt_year,year_min,year_max, &(Time.Current), &Dump,&Options); /*Use the next program to output balance information for indivdual glaciers */ gl_massbalance(&Map, TopoMap, SnowMap,GlacierMap, dt_year,year_min, year_max, &(Time.Current), &Dump); } #endif } if (IsNewDay(Time.DayStep)) { InitNewDay(Time.Current.JDay, &SolarGeo); PrintDate(&(Time.Current), stdout); printf("\n"); } InitNewStep(&InFiles, &Map, &Time, Soil.MaxLayers, &Options, NStats, Stat, InFiles.RadarFile, &Radar, RadarMap, &SolarGeo, TopoMap, SoilMap, MM5Input, WindModel, &MM5Map); /* initialize channel/road networks for time step */ if (Options.HasNetwork) { channel_step_initialize_network(ChannelData.streams); channel_step_initialize_network(ChannelData.roads); } for (y = 0; y < Map.NY; y++) { for (x = 0; x < Map.NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { if (Options.Shading) LocalMet = MakeLocalMetData(y, x, &Map, Time.DayStep, &Options, NStats, Stat, MetWeights[y][x], TopoMap[y][x].Dem, &(RadiationMap[y][x]), &(PrecipMap[y][x]), &Radar, RadarMap, PrismMap, &(SnowMap[y][x]), SnowAlbedo, MM5Input, WindModel, PrecipLapseMap, &MetMap, NGraphics, Time.Current.Month, SkyViewMap[y][x], ShadowMap[Time.DayStep][y][x], SolarGeo.SunMax, SolarGeo.SineSolarAltitude); else LocalMet = MakeLocalMetData(y, x, &Map, Time.DayStep, &Options, NStats, Stat, MetWeights[y][x], TopoMap[y][x].Dem, &(RadiationMap[y][x]), &(PrecipMap[y][x]), &Radar, RadarMap, PrismMap, &(SnowMap[y][x]), SnowAlbedo, MM5Input, WindModel, PrecipLapseMap, &MetMap, NGraphics, Time.Current.Month, 0.0, 0.0, SolarGeo.SunMax, SolarGeo.SineSolarAltitude); /* get surface tempeature of each soil layer */ for (i = 0; i < Soil.MaxLayers; i++) { if (Options.HeatFlux == TRUE) { if (Options.MM5 == TRUE) SoilMap[y][x].Temp[i] = MM5Input[shade_offset + i + N_MM5_MAPS][y][x]; /* read tempeature of each soil layer from met station input */ else SoilMap[y][x].Temp[i] = Stat[0].Data.Tsoil[i]; } /* if heat flux option is turned off, soil temperature of all 3 layers is taken equal to air tempeature */ else SoilMap[y][x].Temp[i] = LocalMet.Tair; } MassEnergyBalance(&Options, y, x, SolarGeo.SineSolarAltitude, Map.DX, Map.DY, Time.Dt, Options.HeatFlux, Options.CanopyRadAtt, Options.Infiltration, Veg.MaxLayers, &LocalMet, &(Network[y][x]), &(PrecipMap[y][x]), &(VType[VegMap[y][x].Veg-1]), &(VegMap[y][x]), &(SType[SoilMap[y][x].Soil-1]), &(SoilMap[y][x]), &(SnowMap[y][x]), &(RadiationMap[y][x]), &(EvapMap[y][x]), &(Total.Rad), &ChannelData, SkyViewMap); PrecipMap[y][x].SumPrecip += PrecipMap[y][x].Precip; } } } /* Average all RBM inputs over each segment */ if (Options.StreamTemp) { channel_grid_avg(ChannelData.streams); if (Options.CanopyShading) CalcCanopyShading(&Time, ChannelData.streams, &SolarGeo); } #ifndef SNOW_ONLY RouteSubSurface(Time.Dt, &Map, TopoMap, VType, VegMap, Network, SType, SoilMap, &ChannelData, &Time, &Options, Dump.Path, MaxStreamID, SnowMap); if (Options.HasNetwork) RouteChannel(&ChannelData, &Time, &Map, TopoMap, SoilMap, &Total, &Options, Network, SType, PrecipMap, LocalMet.Tair, LocalMet.Rh); if (Options.Extent == BASIN) RouteSurface(&Map, &Time, TopoMap, SoilMap, &Options, UnitHydrograph, &HydrographInfo, Hydrograph, &Dump, VegMap, VType, &ChannelData); #endif if (NGraphics > 0) draw(&(Time.Current), IsEqualTime(&(Time.Current), &(Time.Start)), Time.DayStep, &Map, NGraphics, which_graphics, VType, SType, SnowMap, SoilMap, VegMap, TopoMap, PrecipMap, PrismMap, SkyViewMap, ShadowMap, EvapMap, RadiationMap, MetMap, Network, &Options); Aggregate(&Map, &Options, TopoMap, &Soil, &Veg, VegMap, EvapMap, PrecipMap, RadiationMap, SnowMap, SoilMap, &Total, VType, Network, &ChannelData, &roadarea); MassBalance(&(Time.Current), &(Time.Start), &(Dump.Balance), &Total, &Mass); ExecDump(&Map, &(Time.Current), &(Time.Start), &Options, &Dump, TopoMap, EvapMap, RadiationMap, PrecipMap, SnowMap, MetMap, VegMap, &Veg, SoilMap, Network, &ChannelData, &Soil, &Total, &HydrographInfo,Hydrograph); IncreaseTime(&Time); t += 1; } ExecDump(&Map, &(Time.Current), &(Time.Start), &Options, &Dump, TopoMap, EvapMap, RadiationMap, PrecipMap, SnowMap, MetMap, VegMap, &Veg, SoilMap, Network, &ChannelData, &Soil, &Total, &HydrographInfo, Hydrograph); FinalMassBalance(&(Dump.FinalBalance), &Total, &Mass); printf("\nEND OF MODEL RUN\n\n"); /* record the run time at the end of each time loop */ finish1 = clock (); runtime = (finish1-start)/CLOCKS_PER_SEC; printf("***********************************************************************************"); printf("\nRuntime Summary:\n"); printf("%6.2f hours elapsed for the simulation period of %d hours (%.1f days) \n", runtime/3600, t*Time.Dt/3600, (float)t*Time.Dt/3600/24); return EXIT_SUCCESS; }
/******************************************************************************* Function name: InitPixDump() Purpose : Initialize the pixel dumps. This information is in the [OUTPUT] section of the input file Required : LISTPTR Input - Linked list with input strings MAPSIZE *Map - Information about basin extent uchar **BasinMask - Basin mask char *Path - Directory to write output to int NPix - Number of pixels to dump PIXDUMP **Pix - Array of pixels to dump Returns : number of accepted dump pixels (i.e. in the mask, etc) Modifies : NPix and its members Comments : *******************************************************************************/ int InitPixDump(LISTPTR Input, MAPSIZE *Map, uchar **BasinMask, char *Path, int NPix, PIXDUMP **Pix, OPTIONSTRUCT *Options) { char *Routine = "InitPixDump"; char Str[BUFSIZE + 1]; double North; double East; int i; /* counter */ int j; int ok; char temp_name[BUFSIZE + 1]; char KeyName[name + 1][BUFSIZE + 1]; char *KeyStr[] = { "NORTH COORDINATE", "EAST COORDINATE", "NAME" }; char *SectionName = "OUTPUT"; char VarStr[name + 1][BUFSIZE + 1]; ok = 0; if (!(*Pix = (PIXDUMP *)calloc(NPix, sizeof(PIXDUMP)))) ReportError(Routine, 1); for (i = 0; i < NPix; i++) { /* Read the key-entry pairs from the input file */ for (j = 0; j <= name; j++) { sprintf(KeyName[j], "%s %d", KeyStr[j], i + 1); GetInitString(SectionName, KeyName[j], "", VarStr[j], (unsigned long)BUFSIZE, Input); } /* Assign the entries to the appropriate variables */ if (!CopyDouble(&North, VarStr[north], 1)) ReportError(KeyName[north], 51); if (!CopyDouble(&East, VarStr[east], 1)) ReportError(KeyName[east], 51); if (IsEmptyStr(VarStr[name])) ReportError(KeyName[name], 51); strcpy(temp_name, VarStr[name]); /* Convert map coordinates to matrix coordinates */ (*Pix)[i].Loc.N = Round(((Map->Yorig - 0.5 * Map->DY) - North) / Map->DY); (*Pix)[i].Loc.E = Round((East - (Map->Xorig + 0.5 * Map->DX)) / Map->DX); if (!InArea(Map, &((*Pix)[i].Loc)) || !INBASIN(BasinMask[(*Pix)[i].Loc.N][(*Pix)[i].Loc.E])) { printf("Ignoring dump command for pixel named %s \n", temp_name); } else { printf("Accepting dump command for pixel named %s \n", temp_name); sprintf(Str, "%s", temp_name); sprintf((*Pix)[ok].OutFile.FileName, "%sPixel.%s", Path, Str); (*Pix)[ok].Loc.N = (*Pix)[i].Loc.N; (*Pix)[ok].Loc.E = (*Pix)[i].Loc.E; OpenFile(&((*Pix)[ok].OutFile.FilePtr), (*Pix)[ok].OutFile.FileName, "w", TRUE); ok++; } } return ok; }
/***************************************************************************** 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); } }
void main_gl(MAPSIZE *Map, TOPOPIX **TopoMap, SNOWPIX **Snow, GLPIX **GlacierMap, double dt_year, double year_min, double year_max,DATE *Current, DUMPSTRUCT *Dump,OPTIONSTRUCT * Options) { FILE *f_out1, *f_out2 ; double *b, *s_init, *s_out, *swecc, *iwecc, *h_old,*hcc, *b_dot, *s_initcc; double dt_yr; double yr_min; double yr_max; float gl_cov,wsh_gl_cov; float sn_cov, sn_cov_gl; float wsh_sn_cov,wsh_sn_cov_gl,wsh_mask; float h_max; int k; int x; int y; char file_out1[150]; char file_out2[150]; float *Array1; int n_mask; float gl_vol; extern double RHO; extern double A_GLEN ; extern double n_GLEN; extern double C_SLIDE; extern double m_SLIDE; extern double A_tilde; extern double C_tilde; extern double g; extern double dx; extern int N; extern double nm_half; extern double np1; extern double mm_half; extern double m1; // h = malloc(N*sizeof(double)); // ice thickness (vectorized) b = malloc(N*sizeof(double)); // bed surface elevation (vectorized) s_init = malloc(N*sizeof(double)); // initial ice surface elevation (vectorized) s_out = malloc(N*sizeof(double)); // output ice surface elevation (vectorized) b_dot = malloc(N*sizeof(double)); swecc = malloc(N*sizeof(double)); iwecc = malloc(N*sizeof(double)); h_old = malloc(N*sizeof(double)); hcc = malloc(N*sizeof(double)); s_initcc = malloc(N*sizeof(double)); // Array = malloc(N*sizeof(float)); if (!(Array1 = (float *) calloc(Map->NX * Map->NY, sizeof(float)))); dt_yr = dt_year; yr_min = year_min; yr_max = year_max; k = 0; nm_half = (n_GLEN-1)/2; np1 = n_GLEN+1; mm_half = (m_SLIDE-1)/2; m1 = m_SLIDE; n_mask = 0; gl_cov = 0; sn_cov=sn_cov_gl= 0; h_max = 0; gl_cov = 0; gl_vol = 0; wsh_gl_cov = 0; sn_cov= 0; h_max = 0; wsh_sn_cov= wsh_sn_cov_gl=0; wsh_mask = 0; for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++) { k = x*Map->NY + y; if (INBASIN(TopoMap[y][x].Mask)){ swecc[k] = (double)Snow[y][x].Swq - (double)Snow[y][x].sweold; //change in swe in previous month Snow[y][x].sweold = Snow[y][x].Swq; iwecc[k] = (double)Snow[y][x].Iwq - (double)Snow[y][x].iweold; // change in iwe in previous month b_dot[k] = iwecc[k]; //mass gain or loss of glacier layer used in dynamics GlacierMap[y][x].Mbal = iwecc[k]+swecc[k]; GlacierMap[y][x].totmbal = GlacierMap[y][x].Mbal + GlacierMap[y][x].totmbal; b[k] = GlacierMap[y][x].b; s_initcc[k] = GlacierMap[y][x].s_init + b_dot[k]; // change in surface topography due to mass balance if(s_initcc[k] <= b[k]) s_initcc[k] = b[k]; h_old[k] = s_initcc[k] - b[k]; s_init[k] = GlacierMap[y][x].s_init; if (Options->Glacier == GLSTATIC) GlacierMap[y][x].s_out = GlacierMap[y][x].s_init; } else { //b_dot[k] = -20; b[k] = GlacierMap[y][x].b; h_old[k]= 0.0; s_init[k] = b[k]; //printf("h_old= %f", h_old[k]); } } } if (Options->Glacier == GLDYNAMIC) { printf("Glacier Model monthly run (Dynamic)\n"); A_tilde = 2*A_GLEN*pow(RHO*g,n_GLEN)/((n_GLEN+2)*pow(dx,2)); C_tilde = C_SLIDE*pow(RHO*g,m_SLIDE)/pow(dx,2); SetupIndexArrays(); RunGlacier(b, s_init, s_out, yr_min, yr_max, dt_yr, b_dot, Options); } for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++) { if (INBASIN(TopoMap[y][x].Mask)){ if (Options->Glacier == GLDYNAMIC) { k = x*Map->NY + y; GlacierMap[y][x].s_init = s_out[k]; GlacierMap[y][x].s_out = s_out[k]; GlacierMap[y][x].h = GlacierMap[y][x].s_out - GlacierMap[y][x].b; hcc[k] = GlacierMap[y][x].h - h_old[k]; //change in ice thickness due to glacier movement /*Update Glacier Ice Base on Ice Flow Only (Surface Balance Change Already Accounted for)*/ Snow[y][x].Iwq = Snow[y][x].Iwq + (hcc[k] * (900./1000.)); } if(GlacierMap[y][x].GlMask>=1){ Snow[y][x].Iwq = Snow[y][x].Iwq; Snow[y][x].iweold = Snow[y][x].Iwq; } else { /*The following was added to not allow glaciers to exist outside of Glacier Mask*/ /*Do to unavoidable inaccuracies in model inputs, in some cases small glaciers */ /*sometime grow outside of the historical glacier footprint, since they do not contribute to runoff*/ /*but would erroneously contribute in a future warmer climate they are deleted to avoid error*/ /*in future glacier contribution. The amount removed is tracked with the IceRemoved variable*/ Snow[y][x].IceRemoved += Snow[y][x].Iwq; Snow[y][x].Iwq = 0; Snow[y][x].iweold = 0.0; b[k] = GlacierMap[y][x].b; h_old[k]= 0.0; s_init[k] = b[k]; } if(Snow[y][x].Iwq < 0.00){ Snow[y][x].Iwq = 0; Snow[y][x].iweold = 0.0; } /*Only Inluding Pixels with more than 1 meter I.W.E. in extent calculation*/ if(GlacierMap[y][x].GlMask>=1){ n_mask += 1; gl_vol += Snow[y][x].Iwq * dx * dx; if(Snow[y][x].Iwq > 1.0) gl_cov +=1; } if(Snow[y][x].Iwq > 1.0 && GlacierMap[y][x].WshMask==1) wsh_gl_cov +=1; if(Snow[y][x].Swq > 0){ sn_cov +=1; if(Snow[y][x].Iwq > 1.0) sn_cov_gl +=1; } if(GlacierMap[y][x].WshMask==1 && Snow[y][x].Swq > 0){ wsh_sn_cov +=1; if(Snow[y][x].Iwq > 1.0) wsh_sn_cov_gl +=1; } if(GlacierMap[y][x].WshMask==1) wsh_mask +=1; } else { b[k] = GlacierMap[y][x].b; h_old[k]= 0.0; s_init[k] = b[k]; Snow[y][x].Iwq = 0; Snow[y][x].iweold = 0.0; } } } /********************************OUTPUTS*****************************/ sprintf(file_out2, "%sgl_sn_cov.txt", Dump->Path); if((f_out2=fopen(file_out2,"ab"))==NULL) { printf("main(): Cannot open output file %s\n", file_out2); exit(1); } //gl_cov = 100*gl_cov/(float)n_mask; //sn_cov = 100*sn_cov/(float)n_mask; //wsh_gl_cov = 100*wsh_gl_cov/wsh_mask; //wsh_sn_cov = 100*wsh_sn_cov/wsh_mask; //printf("Ice Extent (percent of initial) = %.3f percent\n", 100*gl_cov/(float)n_mask); printf("Watershed Snow-covered area = %.3f percent\n", 100*wsh_sn_cov/wsh_mask); printf("Watershed glacier-covered area = %.3f percent\n", 100*wsh_gl_cov/wsh_mask); fprintf(f_out2,"Ice-covered area (km^2) = %04d %02d %02d %.3f\n",Current->Year,Current->Month,Current->Day, (gl_cov*dx*dx)/1000000); fprintf(f_out2, "Snow-covered area (km^2) = %04d %02d %02d %.3f\n", Current->Year,Current->Month,Current->Day,(sn_cov*dx*dx)/1000000); fprintf(f_out2, "Snow-covered area on glacier surfaces (km^2) = %04d %02d %02d %.3f\n", Current->Year,Current->Month,Current->Day,(sn_cov_gl*dx*dx)/1000000); fprintf(f_out2, "Watershed Snow-covered (km^2) = %04d %02d %02d %.3f\n", Current->Year,Current->Month,Current->Day,(wsh_sn_cov*dx*dx)/1000000); fprintf(f_out2, "Watershed Snow-covered area on glacier surface (km^2) = %04d %02d %02d %.3f\n", Current->Year,Current->Month,Current->Day,(wsh_sn_cov_gl*dx*dx)/1000000); fprintf(f_out2, "Watershed glacier-covered area (km^2) = %04d %02d %02d %.3f\n", Current->Year,Current->Month,Current->Day,(wsh_gl_cov*dx*dx)/1000000); fprintf(f_out2, "Glacier Volume = %04d %02d %02d %.3f\n", Current->Year,Current->Month,Current->Day,gl_vol); sprintf(file_out1, "%sbalance_sum.bin", Dump->Path); if((f_out1=fopen(file_out1,"wb"))==NULL) { printf("main(): Cannot open output file %s\n", file_out1); exit(1); } for (x = 0; x < Map->NX; x++) { for (y = 0; y < Map->NY; y++){ k = x*Map->NY + y; //((float *) Array)[y * Map->NX + x] = b_dot[k]; ((float *) Array1)[y * Map->NX + x] = GlacierMap[y][x].totmbal; } } fwrite(Array1, sizeof(Array1), Map->NY * Map->NX, f_out1); free(Array1); free(b); free(s_out); free(s_init); free(b_dot); free(swecc); free(iwecc); free(hcc); free(h_old); free(s_initcc); fclose(f_out1); fclose(f_out2); printf("ALL DONE: %.2f yr integration\n", yr_max); }
float ElevationSlope(MAPSIZE *Map, TOPOPIX **TopoMap, FINEPIX ***FineMap, int y, int x, int *nexty, int *nextx, int prevy, int prevx, float *Aspect) { int n, direction; float soil_elev[NNEIGHBORS]; float bedrock_elev[NNEIGHBORS]; float Slope; float temp_slope[NNEIGHBORS]; double length_diagonal; float dx, dy, celev; int coarsej, coarsei; /* fill neighbor array */ for (n = 0; n < NNEIGHBORS; n++) { int xn = x + xneighbor[n]; int yn = y + yneighbor[n]; // Initialize soil_elev and bedrock_elev soil_elev[n] = (float) OUTSIDEBASIN; bedrock_elev[n] = (float) OUTSIDEBASIN; // Check whether yn, xn are within FineMap array bounds if (valid_cell_fine(Map,xn,yn)){ coarsej = floor(yn*Map->DMASS/Map->DY); coarsei = floor(xn*Map->DMASS/Map->DX); // Check whether FineMap element has been allocated for this cell // (equivalent to checking whether parent coarse grid cell is within coarse mask) if (INBASIN(TopoMap[coarsej][coarsei].Mask)) { bedrock_elev[n] = (((*FineMap[yn][xn]).Mask) ? (*FineMap[yn][xn]).bedrock : (float) OUTSIDEBASIN); soil_elev[n] = (((*FineMap[yn][xn]).Mask) ? (*FineMap[yn][xn]).bedrock+(*FineMap[yn][xn]).sediment : (float) OUTSIDEBASIN); } } } /* Find bedrock slope in all directions. Negative slope = ascent, positive slope = descent. */ dx = Map->DMASS; dy = Map->DMASS; celev = (*FineMap[y][x]).bedrock; length_diagonal = sqrt((pow(dx, 2)) + (pow(dy, 2))); for (n = 0; n < NNEIGHBORS; n++) { if (bedrock_elev[n] == OUTSIDEBASIN) bedrock_elev[n] = DHSVM_HUGE; if(n==0 || n==2 || n==4 || n==6) temp_slope[n] = (atan((celev - bedrock_elev[n]) / length_diagonal)) * DEGPRAD; else if(n==1 || n==5) temp_slope[n] = (atan((celev - bedrock_elev[n]) / dy)) * DEGPRAD; else temp_slope[n] = (atan((celev - bedrock_elev[n]) / dx)) * DEGPRAD; } /* Find largest (positive) slope, this is the direction of failure along bedrock plain. Backtracking isn't a problem if using the bedrock, but sinks may exist. */ Slope = -999.; *Aspect = -99.; for (n = 0; n < NNEIGHBORS; n++){ if(temp_slope[n] > Slope) { Slope = temp_slope[n]; *Aspect = temp_aspect[n] * PI / 180.0; direction = n; *nexty = y + yneighbor[n]; *nextx = x + xneighbor[n]; } } /* If no positive slope found, a bedrock sink was encountered. Assuming the sink should be filled to the lowest "pour elevation", aspect should have already been assigned correctly. */ /* Find dynamic slope in direction of steepest descent. */ celev = (*FineMap[y][x]).bedrock + (*FineMap[y][x]).sediment; if(direction==0 || direction==2 || direction==4 || direction==6) Slope = (atan((celev - soil_elev[direction]) / length_diagonal)) * DEGPRAD; else if(direction==1 || direction==5) Slope = (atan((celev - soil_elev[direction]) / dy)) * DEGPRAD; else Slope = (atan((celev - soil_elev[direction]) / dx)) * DEGPRAD; /* It is possible that a "soil" sink could be encountered at this point. This is not really an error, and is checked for in MainMWM. */ // if(Slope < 0.0 ) { // fprintf(stderr, "Sink encountered in cell y= %d x= %d, all routes from here go up!\n", y,x); // } if(Slope == -999. || *Aspect == -99.) { fprintf(stderr, "Aspect not assigned, this shouldn't have happened.\n"); exit(0); } return Slope; }
/***************************************************************************** Function name: InitNewStep() Purpose : Initialize Earth-Sun geometry and meteorological data at the beginning of each timestep Required : MAPSIZE Map - Structure with information about location TIMESTRUCT Time - Structure with time information int PrecipType - Type of precipitation input, RADAR, STATION or OROGRAPHIC int FlowGradient - Type of FlowGradient calculation int NStats - Number of meteorological stations METLOCATION *Stat - Structure with information about the meteorological stations in or near the study area char *RadarFileName - Name of file with radar images MAPSIZE Radar - Structure with information about the precipitation radar coverage RADCLASSPIX **RadMap - Structure with radiation data for each pixel RADARPIX **RadarMap - Structure with precipitation information for each radar pixel SOLARGEOMETRY *SolarGeo - structure with information about Earth-Sun geometry SOILPIX **SoilMap - structure with soil information float ***MM5Input - MM5 input maps float ***WindModel - Wind model maps Returns : void Modifies : Comments : To be executed at the beginning of each time step *****************************************************************************/ void InitNewStep(INPUTFILES *InFiles, MAPSIZE *Map, TIMESTRUCT *Time, int NSoilLayers, OPTIONSTRUCT *Options, int NStats, METLOCATION *Stat, char *RadarFileName, MAPSIZE *Radar, RADARPIX **RadarMap, SOLARGEOMETRY *SolarGeo, TOPOPIX **TopoMap, RADCLASSPIX **RadMap, SOILPIX **SoilMap, float ***MM5Input, float ***WindModel, MAPSIZE *MM5Map) { const char *Routine = "InitNewStep"; int i; /* counter */ int j; /* counter */ int x; /* counter */ int y; /* counter */ int NumberType; /* number type in MM5 input */ int Step; /* Step in the MM5 Input */ float *Array = NULL; int MM5Y, MM5X; /* Calculate variables related to the position of the sun above the horizon, this is only necessary if shading is TRUE */ SolarHour(SolarGeo->Latitude, (Time->DayStep + 1) * ((float) Time->Dt) / SECPHOUR, ((float) Time->Dt) / SECPHOUR, SolarGeo->NoonHour, SolarGeo->Declination, SolarGeo->Sunrise, SolarGeo->Sunset, SolarGeo->TimeAdjustment, SolarGeo->SunEarthDistance, &(SolarGeo->SineSolarAltitude), &(SolarGeo->DayLight), &(SolarGeo->SolarTimeStep), &(SolarGeo->SunMax), &(SolarGeo->SolarAzimuth)); /*printf("SunMax is %f\n",SolarGeo->SunMax);*/ if (Options->MM5 == TRUE) { /* Read the data from the MM5 files */ if (!(Array = (float *) calloc(MM5Map->NY * MM5Map->NX, sizeof(float)))) ReportError((char *) Routine, 1); NumberType = NC_FLOAT; Step = NumberOfSteps(&(Time->StartMM5), &(Time->Current), Time->Dt); Read2DMatrix(InFiles->MM5Temp, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_temperature - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } Read2DMatrix(InFiles->MM5Humidity, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_humidity - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } Read2DMatrix(InFiles->MM5Wind, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_wind - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } Read2DMatrix(InFiles->MM5ShortWave, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_shortwave - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } Read2DMatrix(InFiles->MM5LongWave, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_longwave - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } Read2DMatrix(InFiles->MM5Precipitation, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_precip - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; if (MM5Input[MM5_precip - 1][y][x] < 0.0) { printf("Warning: MM5 precip is less than zero %f\n", MM5Input[MM5_precip - 1][y][x]); MM5Input[MM5_precip - 1][y][x] = 0.0; } } Read2DMatrix(InFiles->MM5Terrain, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_terrain - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } Read2DMatrix(InFiles->MM5Lapse, Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[MM5_lapse - 1][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } if (Options->HeatFlux == TRUE) { for (i = 0, j = MM5_lapse; i < NSoilLayers; i++, j++) { Read2DMatrix(InFiles->MM5SoilTemp[i], Array, NumberType, MM5Map->NY, MM5Map->NX, Step); for (y = 0; y < Map->NY; y++) for (x = 0; x < Map->NX; x++) { MM5Y = (int) ((y + MM5Map->OffsetY) * Map->DY / MM5Map->DY); MM5X = (int) ((x - MM5Map->OffsetX) * Map->DX / MM5Map->DY); MM5Input[j][y][x] = Array[MM5Y * MM5Map->NX + MM5X]; } } } free(Array); } /*end if MM5*/ /* if the flow gradient is based on the water table, recalculate the water table gradients. Flow directions are now calculated in RouteSubSurface*/ if (Options->FlowGradient == WATERTABLE) { /* Calculate the WaterLevel, i.e. the height of the water table above some datum */ for (y = 0; y < Map->NY; y++) { for (x = 0; x < Map->NX; x++) { if (INBASIN(TopoMap[y][x].Mask)) { SoilMap[y][x].WaterLevel = TopoMap[y][x].Dem - SoilMap[y][x].TableDepth; } } } /* HeadSlopeAspect(Map, TopoMap, SoilMap); */ } if ((Options->MM5 == TRUE && Options->QPF == TRUE) || Options->MM5 == FALSE) GetMetData(Options, Time, NSoilLayers, NStats, SolarGeo->SunMax, Stat, Radar, RadarMap, RadarFileName); }