import math import numpy as np import matplotlib.pyplot as plt from matplotlib import colors as c import csv import time plt.style.use('_mpl-gallery-nogrid') #Data makes up a grid with grid cell size (total length)/(len(elevData) and #grid dimensions len(elevData) x len(elevData[0]) #get actual elevations from file ''' results = [] with open("subRegion2-5406.csv1801x1286") as csvfile: reader = csv.reader(csvfile, quoting=csv.QUOTE_NONNUMERIC) #change contents to floats for row in reader: # each row is a list results.append(row) elevData = results ''' #Array for Data: elevData = np.array([[None]*5]*5) # in m rainfallData = np.array([[None]*len(elevData[0])]*len(elevData)) #in µm (just due to odd round off errors) absorptionData = np.array([[None]*len(elevData[0])]*len(elevData)) # in µm/min absorptionDataStatic = np.array([[None]*len(elevData[0])]*len(elevData)) # in µm/min totalWaterAbsorbed = 0 # in m^3 #tile dimension #tileDim = 133.5826*1000/5406 # in m #(full interval is 133.5826km wide there are 10812 pieces in full file so 10812/2=5406 pieces so tileDim = 133.5826*1000/5406) #tileDim=5.0/float(len(elevData)) # in m tileDim=10 # in m rain=float(input("How many centimeters of rain should fall?")) #filling the array with some random math to make it more fun ''' i=0 while i < len(elevData): k=0 while(k< len(elevData[0])): elevData[i][k] = math.trunc((20*math.cos(k*math.pi/4)**2+40*i+0.5*i**2+k*1.3)) rainfallData[i][k] = (1.5*math.sin(k)*math.sin(i) + 1.5)*rain/3 #in cm over entire interval (measures total rainfall) absorptionData[i][k] = 5/(10+elevData[i][k]/15) #in cm/min absorptionDataStatic[i][k] = 5/(10+elevData[i][k]/15) #in cm/min k+=1 i+=1 i=0 while(i < len(elevData)): k=0 while(k< len(elevData[0])): #elevData[i][k] = -5*math.exp(-i/4+2)+1500+k rainfallData[i][k] = rain #in cm over entire interval (measures total rainfall) absorptionData[i][k] = 0 #5/(10+elevData[i][k]/15) #in cm/min absorptionDataStatic[i][k] = 0 #5/(10+elevData[i][k]/15) #in cm/min k+=1 i+=1 #cool filling i=0 while(i < len(elevData)): k=0 while k < len(elevData[0]): r=(6*i/(len(elevData)-1)-3) # gives i on the scale -3 to 3 f=(6*k/(len(elevData[0])-1)-3) #similarly gives k on the scale -3 to 3 elevData[i][k] = (math.exp(-1*(r*r*f*f)) - math.exp(-1*(r*r+f*f))+1)*50 #offset to make absorption more consistent rainfallData[i][k] = rain #in µm over entire interval (measures total rainfall) absorptionData[i][k] = 0 #in cm/min absorptionDataStatic[i][k] = 0 #in cm/min k+=1 i+=1 ''' i=0 while(i < len(elevData)): k=0 while k < len(elevData[0]): r=(5*i/(len(elevData)-1)) #gives i on a 0 to 5 range f=(5*k/(len(elevData[0])-1)) #gives k on a 0 to 5 range elevData[i][k] = .2*r+.2*f#+3000 #offset to make absorption more consistent rainfallData[i][k] = rain #in µm over entire interval (measures total rainfall) absorptionData[i][k] = 0 #in cm/min absorptionDataStatic[i][k] = 0 #in cm/min k+=1 i+=1 ''' #filling for accurate ABQ Area i=0 while(i=1/3 and i/(len(elevData)-1)<=2/3): if(k/(len(elevData[0])-1)>=1/3 and k/(len(elevData[0])-1)<=1/2): if(elevData[i][k]>=1520): #if in river isn't city absorptionData[i][k] = 1/2*absorptionData[i][k] #cut absorption in half #if subset the these proportions for heavy urbanization if(i/(len(elevData)-1)<=.7767 and k/(len(elevData[0])-1)<=.5393): absorptionData[i][k] = 1/2*absorptionData[i][k] #cut absorption in half absorptionDataStatic[i][k] = absorptionData[i][k] #in cm/min k+=1 i+=1 ''' #Initializing printAbsorb = False printExtras = False printExtras2 = False printResults = False printFiles = False percentGoal = 1 #choose which way to calculate newMethod = True oldMethod = not(newMethod) recalculation = True if(input("Initializing Data? (y/n)") == "y"): print("Elevation Data: ",elevData) print("Min: ",np.min(elevData)) print("Max: ",np.max(elevData)) print("Rainfall Data: ",rainfallData) printExtensivityLevel = int(input("What level of extra data is requested? (0 to 2) (none to a lot)")) if(printExtensivityLevel == 0): printExtras = False printExtras2 = False elif(printExtensivityLevel == 1): printExtras = True printExtras2 = False elif(printExtensivityLevel == 2): printExtras = True printExtras2 = True if(input("Print preliminary results? (y/n)")=="y"): printResults = True else: printResults = False if(input("Print files? (y/n)")=="y"): printFiles = True else: printFiles = False timescale = int(input("How long should the rainfall be spread out over? (minutes)")) addition = int(input("How long should the model run after the rain has stopped? (minutes)")) timescale += addition #One limitation of the my algorithmn is that it only allows water to travel one pixel per tick at the maximum which could prove quite misrepresentative when having huge numbers of pixels and limited ticks (thus the need to really kick up the tick number when using large datasets) accuracy = int(input("Into how many pieces should the program break up the interval? (more pieces --> more accurate) (pieces > total min of simulation recommended)")) #Potentially precalculate water flow per cell here currentSurfaceWater = np.array([[0.0]*len(elevData[0])]*len(elevData)) futureSurfaceWater = np.array([[0.0]*len(elevData[0])]*len(elevData)) #to be added next tick #Initialized for use later in loops problemAreas = np.array([[0]*len(elevData[0])]*len(elevData)) erosionAreas = np.array([[0]*len(elevData[0])]*len(elevData)) waterMovement = np.array([[0.0]*len(elevData[0])]*len(elevData)) waterDeficitArr = np.array([[0.0]*len(elevData[0])]*len(elevData)) stepSize = timescale/accuracy #for rain and absorption print("Step size: ",stepSize, "min") print("tileDim: ", tileDim, "m") #To speed up calculation time the proportions of flowig water will be precalculated flows = np.array([[[0.0]*len(elevData[0])]*len(elevData)]*8) flowsTemp = np.array([[[0.0]*len(elevData[0])]*len(elevData)]*8) #the first set of brackets in flows gives the direction in which the flow is to be done eg: flows[0] gives the flows north # 0 is north, up, or decreasing in i # 1 is northeast, diagonally up right, or increasing k and decreasing i # 2 is east, right, or increasing in k # 3 is southeast, diagonally down right, or increasing k and i # 4 is south, down, or increasing i # 5 is southwest, diagonally down left, or decreasing k and increasing i # 6 is west, left, or decreasing k # 7 is northwest, diagonally up left, or decreasing k and i #important to note that these directions might not reflect the real north of the data #they are really just to help visualize the directions of traversal and checking for this array. # Actual fluid dnyamics equations give (after isolated and integrated) that total volumetric flow of liquid on a plane through a rectange (l*d). Source: https://ocw.mit.edu/courses/12-090-introduction-to-fluid-motions-sediment-transport-and-current-generated-sedimentary-structures-fall-2006/72c0d3ee9656652db67315787b47c7a8_ch4.pdf # Kinda common knowledge ish (?) # is given by: # 2/3*d^3*9.8m/s^2*1g/cm^3*sin(α)/(1.308mPa*s)*l= 2/3*9.8/1.308*m*g/(s^3*cm^3*g/ms^2)*l=2/3*9.8/1.308*m^2/(s*cm^3)*(100cm/m)^3*l=2/3*9.8*100^3/1.308/sm*l # Which can be simplified to # 4994903*sin(α)*d^3*l # -------------------- gives cm^3/s # s*m # This is an issue as my model works in depth not volume, so to fix this, dividing this change in volume by the area it affects (tileDim*tileDim), # gives the change in depth for the whole model. # 4994903*sin(α)*d^3*l # -------------------- # s*m*tileDim^2 # Finding l is also a bit strange: l could feasibly be tileDim for linearly adjacent tiles but what happens then for diagonals? # To avoid counting borders as passing water from two different calculations the entire perimeter (4*tileDim) will be broken up among the adjacent # tiles (numbering 8) so each tile will recieve 1/2*tileDim as its l to run water through and thus 1/2*tileDim = l can be substituted in: # 4994903*sin(α)*d^3*1/2*tileDim 2497451.5*sin(α)*d^3 # ----------------------------- = -------------------- # s*m*tileDim^2 s*m*tileDim # Since however, d is in cm we should convert the meters in the bottom to cm so we get 24974.515 as the leading coefficient # Likewise we need to convert the tileDim which is in m to cm thus the coefficient is 249.74515 # Since we are getting cm/s out of this equation we need to multiply by the stepSize with a conversion from s to min to get the real water depth change per step so the final coefficient is 14984.709 # flows gives the precalculable part of this: the 14984.709*sin(α)*stepSize # ------------------------------ # tileDim # Which will be consequently multiplied by the variable part during the looped section of the algorithm: the depth of water cubed startF = time.time() i=0 while(i= home):#conversion cm --> m # - X - flows[0][i][k] = 0 #if its higher just stop # - - - else: α=math.atan((home - elevData[i-1][k])/tileDim) flows[0][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[0][i][k]<(10**-6)): flows[0][i][k]=0 #consider northeastern tile if(i!=0 and k!=len(elevData[0])-1): #check if exists # - - 1 if(elevData[i-1][k+1] >= home): # - X - flows[1][i][k] = 0 # - - - else: α=math.atan((home - elevData[i-1][k+1])/(math.sqrt(2)*tileDim)) #multiplied by √2 because √2*tileDim is the true distance of the diagonal flows[1][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[1][i][k]<(10**-6)): flows[1][i][k]=0 #consider eastern tile # - - - if(k!=len(elevData[0])-1): #exists? # - X 2 if(elevData[i][k+1] >= home): # - - - flows[2][i][k] = 0 else: α=math.atan((home - elevData[i][k+1])/tileDim) flows[2][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[2][i][k]<(10**-6)): flows[2][i][k]=0 #consider southeastern tile if(k!=len(elevData[0])-1 and i!=len(elevData)-1): # - - - if(elevData[i+1][k+1]>=home): # - X - flows[3][i][k] = 0 # - - 3 else: α=math.atan((home - elevData[i+1][k+1])/(math.sqrt(2)*tileDim)) flows[3][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[3][i][k]<(10**-6)): flows[3][i][k]=0 #consider southern tile if(i!=len(elevData)-1): # - - - if(elevData[i+1][k]>=home): # - X - flows[4][i][k] = 0 # - 4 - else: α=math.atan((home - elevData[i+1][k])/tileDim) flows[4][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[4][i][k]<(10**-6)): flows[4][i][k]=0 #consider southwestern tile if(i!=len(elevData)-1 and k!=0): # - - - if(elevData[i+1][k-1]>=home): # - X - flows[5][i][k] = 0 # 5 - - else: α=math.atan((home - elevData[i+1][k-1])/(math.sqrt(2)*tileDim)) flows[5][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[5][i][k]<(10**-6)): flows[5][i][k]=0 #consider western tile if(k!=0): # - - - if(elevData[i][k-1]>=home): # 6 X - flows[6][i][k] = 0 # - - - else: α=math.atan((home - elevData[i][k-1])/tileDim) flows[6][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[6][i][k]<(10**-6)): flows[6][i][k]=0 #consider northwestern tile if(k!=0 and i!=0): # 7 - - if(elevData[i-1][k-1]>=home): # - X - flows[7][i][k] = 0 # - - - else: α=math.atan((home - elevData[i-1][k-1])/(math.sqrt(2)*tileDim)) flows[7][i][k]= ((14984.709)*math.sin(α)*stepSize)/tileDim if(flows[7][i][k]<(10**-6)): flows[7][i][k]=0 k+=1 i+=1 t=0 while(t < timescale): start = time.time() if(t >= timescale - addition): #print("rain done") i=len(elevData) else: i=0 #complete rainfall + absorption while(i Would need additional controls #Following approach is more natural for what water truely does ''' lowest = elevArray[0] lowest2 = elevArray[0] lowestCoord = np.array([tempArr[0],tempArr[1]]) lowestCoord2 = np.array([tempArr[0],tempArr[1]]) n=0 # code finds lowest in whole while(n won't run #Different approach: #Determine which are higher than the center and send water proportionally to the percentage of toptal drop homeElev = elevArray[0] totalDeficit = 0 realWaterDeficit = 0 coordsArr = np.array([], dtype= int) #if the tile is higher or equal to home +currentSurfaceWater declinesArr will not be overwritten thus if they are all set to homeElev +currentSurfaceWater then if the tile is #higher or equal to and the declinesArr value is not changed then the resulting rate from the equation is 0 declinesArr = np.array([homeElev+currentSurfaceWater[i][k]/100]*8, dtype= float) totalRate = 0 waterRateArr = np.array([0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]) #iterate through elevArray and pick out lowers #print(directionArr) #print(elevArray) n=1 while(n=home): #if north is taller if(realNorthElevhome and realNorthElev=realHomeElev): #if its taller in real elevation #recalculate waterRateArr[0]=0 if(printExtras): print("waterRateArr[0] 3: ",waterRateArr[0]) #elif(realNorthElev=home): #if taller if(realNortheastElevhome and realNortheastElev=realHomeElev): #if taller in real elevation #recalculate waterRateArr[1]=0 if(printExtras): print("waterRateArr[1] 3: ",waterRateArr[1]) #elif(realNortheastElev=home): #if taller if(realEastElevhome and realEastElev=realHomeElev): #if taller in real elevation #recalculate waterRateArr[2]=0 if(printExtras): print("waterRateArr[2] 3: ",waterRateArr[2]) #elif(realEastElev=home): #if taller if(realSoutheastElevhome and realSoutheastElev=realHomeElev): #if taller in real elevation #recalculate waterRateArr[3]=0 if(printExtras): print("waterRateArr[3] 3: ",waterRateArr[3]) #elif(realSoutheastElev=home): #if taller if(realSouthElevhome and realSouthElev=realHomeElev): #if its taller in real elevation #recalculate waterRateArr[4]=0 if(printExtras): print("waterRateArr[4] 3: ",waterRateArr[4]) #elif(realSouthElev=home): #if taller if(realSouthwestElevhome and realSouthwestElev=realHomeElev): #if taller in real elevation #recalculate waterRateArr[5]=0 if(printExtras): print("waterRateArr[5] 3: ",waterRateArr[5]) #elif(realSouthwestElev=home): #if taller if(realWestElevhome and realWestElev=realHomeElev): #if its taller in real elevation #recalculate waterRateArr[6]=0 if(printExtras): print("waterRateArr[6] 3: ",waterRateArr[6]) #elif(realWestElev=home): #if taller if(realNorthwestElevhome and realNorthwestElev=realHomeElev): #if taller in real elevation #recalculate waterRateArr[7]=0 if(printExtras): print("waterRateArr[7] 3: ",waterRateArr[7]) #elif(realNorthwestElevcurrentSurfaceWater[i][k]): percentWater = (waterRateArr[n])/totalRate #if the system can't drain all the water there then simply drain what can be drained if(totalRate<=currentSurfaceWater[i][k]): #percent water equals the rate divided by what is there because then when it is multiplied by what is there to get the actual water #it returns the actual rate if(currentSurfaceWater[i][k]!=0): percentWater = waterRateArr[n]/currentSurfaceWater[i][k] else: percentWater = 0 waterToGo = percentWater*currentSurfaceWater[i][k] homeElev = elevData[i][k]+currentSurfaceWater[i][k]/100 #real elevation if(waterToGo!=0): #if tile doesn't exist water to go is zero if(n==0): #if(waterToGo>homeElev-elevData[i-1][k]-currentSurfaceWater[i-1][k]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i-1][k]-currentSurfaceWater[i-1][k] futureSurfaceWater[i-1][k] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i-1," ",k) print("Future water", futureSurfaceWater[i-1][k]) elif(n==1): #if(waterToGo>homeElev-elevData[i-1][k+1]-currentSurfaceWater[i-1][k+1]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i-1][k+1]-currentSurfaceWater[i-1][k+1] futureSurfaceWater[i-1][k+1] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i-1," ",k+1) print("Future water", futureSurfaceWater[i-1][k+1]) elif(n==2): #if(waterToGo>homeElev-elevData[i][k+1]-currentSurfaceWater[i][k+1]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i][k+1]-currentSurfaceWater[i][k+1] futureSurfaceWater[i][k+1] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i," ",k+1) print("Future water", futureSurfaceWater[i][k+1]) elif(n==3): #if(waterToGo>homeElev-elevData[i+1][k+1]-currentSurfaceWater[i+1][k+1]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i+1][k+1]-currentSurfaceWater[i+1][k+1] futureSurfaceWater[i+1][k+1] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i+1," ",k+1) print("Future water", futureSurfaceWater[i+1][k+1]) elif(n==4): #if(waterToGo>homeElev-elevData[i+1][k]-currentSurfaceWater[i+1][k]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i+1][k]-currentSurfaceWater[i+1][k] futureSurfaceWater[i+1][k] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i+1," ",k) print("Future water", futureSurfaceWater[i+1][k]) elif(n==5): #if(waterToGo>homeElev-elevData[i+1][k-1]-currentSurfaceWater[i+1][k-1]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i+1][k-1]-currentSurfaceWater[i+1][k-1] futureSurfaceWater[i+1][k-1] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i+1," ",k-1) print("Future water", futureSurfaceWater[i+1][k-1]) elif(n==6): #if(waterToGo>homeElev-elevData[i][k-1]-currentSurfaceWater[i][k-1]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i][k-1]-currentSurfaceWater[i][k-1] futureSurfaceWater[i][k-1] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i," ",k-1) print("Future water", futureSurfaceWater[i][k-1]) elif(n==7): #if(waterToGo>homeElev-elevData[i-1][k-1]-currentSurfaceWater[i-1][k-1]): #if it wants to flow more than the actual difference in height just do the difference in height #waterToGo=homeElev-elevData[i-1][k-1]-currentSurfaceWater[i-1][k-1] futureSurfaceWater[i-1][k-1] += waterToGo realWaterDeficit += waterToGo if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i-1," ",k-1) print("Future water", futureSurfaceWater[i-1][k-1]) if(printExtras): print("Percent Water: ",percentWater) print("Tile: ", i," ",k) print("Future water", futureSurfaceWater[i][k]) n+=1 #account for water drained #Watch for high flow for erosion check for high values of currentSurfaceWater leaving #(but check proportionally to stepSize such that if a certain amount is flowing **per minute** #it will trigger and add it to a list if(realWaterDeficit/stepSize*tileDim/currentSurfaceWater[i][k]>35*60): #<-- 35cm/s is cause for concern and given the current surface water is water for a time unit stepSize just moving it from one side to another #2cm/min over a tileDim*tileDim through a d*tileDim hole make a velocity of flow erosionAreas[i][k] = 1 #can't apply water deficits yet because what if tile is drained by this then a tile in later on is adjacent to it and flows into that 'empty' tile #need to wait to apply deficit same way need to wait to apply future water waterDeficitArr[i][k] = realWaterDeficit waterMovement[i][k] = totalRate k+=1 i+=1 #Whether data is wanted if(printExtras): print("future surface water: ") print(futureSurfaceWater) print("water deficit:") print(waterDeficitArr) if(printResults): X, Y = np.meshgrid(np.linspace(0, len(elevData[0])-1, len(elevData[0])), np.linspace(0, len(elevData)-1, len(elevData))) Z = waterMovement/stepSize fig, ax = plt.subplots() #Build a 2D mesh with previous values of X and Y and overlay Z values as color print("Water Movement:") print("Max: ",np.amax(Z)/stepSize," cm/min") print("Scale: 0-10cm") ax.pcolormesh(X, Y, Z, vmin=0, vmax=5) plt.show() #Now that all water has been moved: Add future to current and set to zero #also remove the water from current that has been moved i=0 while(i5): #5cm of standing water is ~2in which is enough to damage structures #essentially boolean value problemAreas[i][k] = 1 k+=1 i+=1 #Update Rainfall according to careful exponential decay function: https://www.desmos.com/calculator/wm53ucf5aq i=0 while(ipercentGoal): #such that it only prints out 100 updates at most (just cause its annoying scrolling through 520 percent done updates) #construct a string with - proportional to percent finished result = "(" while(percentDone > 1/40): result+="-" percentDone -= 1/20 #twenty because twenty digits in bar #fill rest with 0s while(len(result)<=20): result+="0" result += ")" print(result) if(printFiles): string1 = "currentWater%d.csv" % (int(percentGoal)) np.savetxt(string1, currentSurfaceWater, delimiter=",") percentDone = t/timescale if(percentDone*100>percentGoal): #just always print percent done if(percentDone<=1): end = time.time() print("Percent Done: ", math.trunc(percentDone*1000)/10,"% -- ", (end - start), "seconds") percentGoal+=1 #string1 = "currentWater%f.csv" % (t) #np.savetxt(string1, currentSurfaceWater, delimiter=",") #algorithm done --> process and print results endF = time.time() print("Total Elapsed Time: ", math.trunc((endF-startF)*1000)/1000) print("Current Surface Water: ",currentSurfaceWater) #rebuild X and Y X, Y = np.meshgrid(np.linspace(0, len(elevData[0])-1, len(elevData[0])), np.linspace(0, len(elevData)-1, len(elevData))) #build z values Z = currentSurfaceWater fig, ax = plt.subplots() #Build a 2D mesh with previous values of X and Y and overlay Z values as color print("Final Surface Water:") print("Max: ",np.amax(Z), "cm") print("Scale: 0-10 cm") ax.pcolormesh(X, Y, Z, vmin=0, vmax=10) plt.show() fig, ax = plt.subplots() print("Final Surface Water:") print("Max: ",np.amax(Z), "cm") print("Scale: 0-",np.amax(Z)," cm") ax.pcolormesh(X, Y, Z, vmin=0, vmax=np.amax(Z)) plt.show() #Print Problem Areas: Z = np.array(problemAreas, dtype = float) #dtype float is essentially just to make it cooperate with being assigned to the same Z that other float arrays have been assigned to earlier in the program fig, ax = plt.subplots() print("Problem Areas:") ax.pcolormesh(X, Y, Z, vmin=0, vmax=1) plt.show() #Print Erosion Problem Areas: Z = np.array(erosionAreas, dtype = float) fig, ax = plt.subplots() print("Erosion Problem Areas:") ax.pcolormesh(X, Y, Z, vmin=0, vmax=1) plt.show() #print real elevations i=0 while(i tie back to problem or how to get there from what you have if there isn't #enough time for implimentation # inspiration from Utah State University Hydrology Program and Methodology # absorption differentiation