Skip to content

Commit 16297a2

Browse files
committed
new_commit
1 parent 761ac08 commit 16297a2

File tree

6 files changed

+368
-307
lines changed

6 files changed

+368
-307
lines changed

code/CURVE.py

Lines changed: 284 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os
66
import utm
77
import numpy as np
8+
import pandas as pd
89
from osgeo import gdal, gdal_array, osr
910
import matplotlib.pyplot as plt
1011

@@ -38,10 +39,145 @@ def pick(c, r, mask): # (c_number, r_number, an array of 1 amd 0)
3839
fill.add(south)
3940
return picked
4041

42+
def expand(array, n): # (an array of 1 and 0, number of additional pixels)
43+
expand = array - array
44+
for i in range(len(array)):
45+
for j in range(len(array[i])):
46+
if array[i][j] == 1:
47+
for k in range(max(0, i-n), min(i+n, len(array)-1)):
48+
for l in range(max(0, j-n), min(j+n, len(array[i])-1)):
49+
expand[k][l] = 1
50+
continue
51+
else:
52+
continue
53+
return expand
4154

55+
# Check for best fit curve
56+
def best_fit_degree (xdata, ydata):
57+
import numpy as np
58+
import matplotlib.pyplot as plt
59+
from sklearn.metrics import r2_score
60+
61+
# Maximum degree for polynomial regression
62+
max_degree = 5
63+
64+
# Lists to store R-squared values and RMSEs for each degree
65+
r_squared_values = []
66+
rmse_values = []
67+
68+
for degree in range(1, max_degree + 1):
69+
# Perform polynomial regression
70+
coefficients = np.polyfit(xdata, ydata, degree)
71+
p = np.poly1d(coefficients)
72+
73+
# Calculate fitted values and residuals
74+
ydata_fit = p(xdata)
75+
residuals = ydata - ydata_fit
76+
77+
# Calculate R-squared using NumPy
78+
r_squared = r2_score(ydata, ydata_fit)
79+
r_squared_values.append(r_squared)
80+
81+
# Calculate RMSE
82+
rmse = np.sqrt(np.mean(residuals ** 2))
83+
rmse_values.append(rmse)
84+
85+
# # Plotting R-squared values and RMSEs for different degrees
86+
# plt.figure(figsize=(10, 4))
87+
88+
# # Plot R-squared values
89+
# plt.subplot(1, 2, 1)
90+
# plt.plot(range(1, max_degree + 1), r_squared_values, marker='o')
91+
# plt.xlabel('Polynomial Degree')
92+
# plt.ylabel('R-squared')
93+
# plt.title('R-squared vs Polynomial Degree')
94+
95+
# # Plot RMSE values
96+
# plt.subplot(1, 2, 2)
97+
# plt.plot(range(1, max_degree + 1), rmse_values, marker='o', color='orange')
98+
# plt.xlabel('Polynomial Degree')
99+
# plt.ylabel('RMSE')
100+
# plt.title('RMSE vs Polynomial Degree')
101+
102+
# plt.tight_layout()
103+
# plt.show()
104+
105+
# score1 = np.diff((rmse_values[0]-rmse_values)/rmse_values[0]*100)
106+
# score2 = -np.diff((r_squared_values[0]-r_squared_values)/r_squared_values[0]*100)
107+
# rmse_pos = int(np.where(score1 == min(score1))[0]) + 1
108+
# r_squared_pos = int(np.where(score2 == min(score2))[0]) + 1
109+
110+
rmse_pos = int(np.where(rmse_values == min(rmse_values))[0]) + 1
111+
r_squared_pos = int(np.where(r_squared_values == max(r_squared_values))[0]) + 1
112+
113+
return round((rmse_pos + r_squared_pos)/2)-1
114+
115+
116+
# Curve fitting ========================>
117+
def curve_fit(xdata, ydata, bf_degree):
118+
import numpy as np
119+
import matplotlib.pyplot as plt
120+
121+
# Perform polynomial regression (adjust the degree as needed)
122+
degree = bf_degree # Example degree of the polynomial
123+
coefficients = np.polyfit(xdata, ydata, degree)
124+
p = np.poly1d(coefficients)
125+
126+
# Generate area values for smoother curve plotting
127+
xdata_values = np.linspace(min(xdata), max(xdata), 1000)
128+
129+
# Calculate corresponding elevation values using the fitted polynomial
130+
ydata_fit = p(xdata_values)
131+
132+
# # Plotting the original data and the fitted curve
133+
# plt.figure()
134+
# plt.scatter(ydata, xdata, label='Original Data')
135+
# plt.plot(ydata_fit, xdata_values, label='Fitted Curve', color='red')
136+
# plt.xlabel('Elevation')
137+
# plt.ylabel('Area')
138+
# plt.title('Area vs Elevation with Fitted Curve')
139+
# plt.legend()
140+
# plt.grid(True)
141+
# plt.show()
142+
# plt.savefig('Fitted_areaVSelevation.png', dpi=600, bbox_inches='tight')
143+
144+
out = np.column_stack((ydata_fit, xdata_values))
145+
return out
42146

147+
# Curve extrapolation (area tends to zero) =================================================================
148+
def curve_extrapolate(xdata, ydata, bf_degree):
149+
import numpy as np
150+
import matplotlib.pyplot as plt
151+
152+
# Perform polynomial regression (using a 4th-degree polynomial as an example)
153+
degree = bf_degree
154+
coefficients = np.polyfit(xdata, ydata, degree)
155+
p = np.poly1d(coefficients)
156+
157+
# Generate area values approaching zero for extrapolation
158+
extrapolated_xdata_values = np.linspace(0, max(xdata), 1000)
159+
#extrapolated_area_values = np.linspace(max(area), 1.5*max(area), 1000)
160+
# Use the polynomial function to extrapolate elevation values for small area values
161+
extrapolated_ydata_values = p(extrapolated_xdata_values)
162+
163+
# Plotting the fitted curve and extrapolated values
164+
plt.figure()
165+
plt.plot(ydata, xdata, 'o', label='Original Data')
166+
plt.plot(extrapolated_ydata_values, extrapolated_xdata_values, label='Extrapolated Curve', color='red')
167+
plt.ylabel('Area')
168+
plt.xlabel('Elevation')
169+
plt.title('Extrapolation of Elevation for Small Area Values')
170+
plt.legend()
171+
plt.grid(True)
172+
plt.show()
173+
#plt.savefig('Extrapolated_areaVSelevation.png', dpi=600, bbox_inches='tight')
174+
175+
out = np.column_stack((extrapolated_ydata_values, extrapolated_xdata_values))
176+
return out
177+
178+
# DEM-based reservoir isolation =============================
43179
def res_isolation(res_name, max_wl, point, boundary, res_directory):
44-
# ===================================================== INPUT PARAMETERS
180+
45181
os.chdir(res_directory + "/Outputs")
46182
res_dem_file = (res_name + "_DEM_UTM_CLIP.tif")
47183

@@ -52,7 +188,7 @@ def res_isolation(res_name, max_wl, point, boundary, res_directory):
52188

53189
dem_bin = gdal_array.LoadFile(res_dem_file).astype(np.float32)
54190
dem_bin[dem_bin == 32767] = np.nan
55-
dem_bin[np.where(dem_bin > max_wl+10)] = 0 #to expand the reservoir extent for accounting uncertainity in max_wl
191+
dem_bin[np.where(dem_bin > max_wl+10)] = 0 #to expand the reservoir extent (10m extra) for accounting uncertainity in max_wl
56192
dem_bin[np.where(dem_bin > 0)] = 1
57193
res_iso = pick(xp, yp, dem_bin)
58194
aa=sum(sum(res_iso))
@@ -85,8 +221,8 @@ def res_isolation(res_name, max_wl, point, boundary, res_directory):
85221

86222
#------------------ Visualization <Start>
87223
plt.figure()
88-
plt.imshow(res_iso, cmap='viridis')
89-
plt.scatter([xp], [yp], c='r', s=10)
224+
# plt.imshow(res_iso, cmap='viridis')
225+
# plt.scatter([xp], [yp], c='r', s=10)
90226
plt.imshow(dem_bin, cmap='viridis')
91227
plt.scatter([xp], [yp], c='r', s=20)
92228
plt.title('DEM-based reservoir isolation')
@@ -97,8 +233,90 @@ def res_isolation(res_name, max_wl, point, boundary, res_directory):
97233
"res_iso.tif", format="GTiff",
98234
prototype = res_dem_file)
99235

236+
return xp, yp
237+
238+
100239
#============================================================== E-A relationship
101-
def curve(res_name, res_directory):
240+
def curve_preDEM(res_name, point_loc, res_directory):
241+
# caculating reservoir surface area and storage volume coresponding to each water level
242+
os.chdir(res_directory + "/Outputs")
243+
res_dem_file = (res_name + "_DEM_UTM_CLIP.tif")
244+
dem_bin = gdal_array.LoadFile(res_dem_file).astype(np.float32)
245+
dem_bin[dem_bin == 32767] = np.nan
246+
[xp, yp]= point_loc
247+
dem_val = int(dem_bin[yp,xp])
248+
249+
results = [["Level (m)", "Area (skm)", "Storage (mcm)"]]
250+
pre_area = 0
251+
tot_stor = 0
252+
for i in range(dem_val, dem_val+30):
253+
level = i
254+
water_px = gdal_array.LoadFile(res_dem_file).astype(np.float32)
255+
water_px[water_px == 32767] = np.nan
256+
water_px[np.where(water_px < dem_val)] = np.nan
257+
water_px[np.where(water_px > i)] = 0
258+
water_px[np.where(water_px > 0)] = 1
259+
res_iso = pick(xp, yp, water_px)
260+
area = np.nansum(res_iso)*9/10000
261+
storage = (area + pre_area)/2
262+
tot_stor += storage
263+
pre_area = area
264+
results = np.append(results, [[level, round(area,4), round(tot_stor,4)]],
265+
axis=0)
266+
267+
# Extract column 2 and 3 from the array
268+
data = results[1:, :]
269+
data = np.array(data, dtype=np.float32)
270+
area = data[:, 1] # area
271+
elevation = data[:, 0] # elevation (ydata)
272+
273+
# Function calling to get best-fit degree of polinomial
274+
bf_degree = best_fit_degree(area, elevation)
275+
276+
# Function calling to get best-fit E-A-S curve values
277+
#EA_curve = curve_fit(area, elevation, bf_degree) # This curve represents the characteristics of DEM outside the reservoir
278+
279+
# Function calling to extrapolate the best-fit to get E-A-S values
280+
EA_curve_extrapolated = curve_extrapolate(area, elevation, bf_degree)
281+
282+
updated_results = [["Level (m)", "Area (skm)", "Storage (mcm)"]]
283+
pre_area = 0
284+
tot_stor = 0
285+
initial_elevation = EA_curve_extrapolated[0,0]
286+
for i in range(0, len(EA_curve_extrapolated)):
287+
level = EA_curve_extrapolated[i,0]
288+
area = EA_curve_extrapolated[i,1]
289+
effective_height = EA_curve_extrapolated[i,0] - initial_elevation
290+
storage = (area + pre_area)/2*(effective_height)
291+
tot_stor += storage
292+
pre_area = area
293+
initial_elevation = EA_curve_extrapolated[i,0]
294+
updated_results = np.append(updated_results, [[level, round(area,4), round(tot_stor,4)]],
295+
axis=0)
296+
297+
# saving output as a csv file
298+
with open('Curve_' + res_name + '.csv',"w", newline='') as my_csv:
299+
csvWriter = csv.writer(my_csv)
300+
csvWriter.writerows(updated_results)
301+
302+
# ==================== Plot the DEM-based Level-Storage curve
303+
data = updated_results[1:, :]
304+
data = np.array(data, dtype=np.float32)
305+
# Create the scatter plot
306+
plt.figure()
307+
plt.scatter(data[:,0], data[:,2], s=5, c='red')
308+
# Set labels and title
309+
plt.xlabel('Level (m)')
310+
plt.ylabel('Storage (mcm)')
311+
plt.title(res_name)
312+
plt.savefig(res_name+'_storageVSelevation.png', dpi=600, bbox_inches='tight')
313+
314+
return round(data[0,0])
315+
316+
317+
318+
#============================================================== E-A relationship
319+
def curve_postDEM(res_name, res_directory):
102320
# caculating reservoir surface area and storage volume coresponding to each water level
103321
os.chdir(res_directory + "/Outputs")
104322
res_dem_file = (res_name + "_DEM_UTM_CLIP.tif")
@@ -107,9 +325,10 @@ def curve(res_name, res_directory):
107325

108326
exp_mask = gdal_array.LoadFile("Expanded_Mask.tif").astype(np.float32)
109327
res_dem[np.where(exp_mask == 0)] = np.nan
110-
gdal_array.SaveArray(res_dem.astype(gdal_array.numpy.float32),
328+
output = gdal_array.SaveArray(res_dem.astype(gdal_array.numpy.float32),
111329
"DEM_Landsat_res_iso.tif",
112330
format="GTiff", prototype = res_dem_file)
331+
output = None
113332
# plt.figure()
114333
# plt.imshow(res_dem, cmap='jet')
115334
# plt.colorbar()
@@ -133,27 +352,80 @@ def curve(res_name, res_directory):
133352
results = np.append(results, [[level, round(area,4), round(tot_stor,4)]],
134353
axis=0)
135354

355+
# Extract column 2 and 3 from the array
356+
data = results[1:, :]
357+
data = np.array(data, dtype=np.float32)
358+
area = data[:, 1] # area
359+
elevation = data[:, 0] # elevation (ydata)
360+
361+
# Function calling to get best-fit degree of polinomial
362+
from scipy.interpolate import interp1d
363+
interpolation_function = interp1d(area, elevation, kind='linear', fill_value='extrapolate')
364+
new_area_values = np.linspace(min(area), max(area), 500)
365+
interpolated_elevation_values = interpolation_function(new_area_values)
366+
367+
# Function calling to get best-fit E-A-S curve values
368+
EA_curve = np.column_stack((interpolated_elevation_values, new_area_values))
369+
370+
updated_results = [["Level (m)", "Area (skm)", "Storage (mcm)"]]
371+
pre_area = 0
372+
tot_stor = 0
373+
initial_elevation = EA_curve[0,0]
374+
for i in range(0, len(EA_curve)):
375+
level = EA_curve[i,0]
376+
area = EA_curve[i,1]
377+
effective_height = EA_curve[i,0] - initial_elevation
378+
storage = (area + pre_area)/2*(effective_height)
379+
tot_stor += storage
380+
pre_area = area
381+
initial_elevation = EA_curve[i,0]
382+
updated_results = np.append(updated_results, [[level, round(area,4), round(tot_stor,4)]],
383+
axis=0)
384+
136385
# saving output as a csv file
137386
with open('Curve_' + res_name + '.csv',"w", newline='') as my_csv:
138387
csvWriter = csv.writer(my_csv)
139-
csvWriter.writerows(results)
388+
csvWriter.writerows(updated_results)
140389

141390
# ==================== Plot the DEM-based Level-Storage curve
142-
data = results[1:, :]
391+
data = updated_results[1:, :]
143392
data = np.array(data, dtype=np.float32)
144-
# Extract column 2 and 3 from the array
145-
column_1 = data[:, 0]
146-
column_3 = data[:, 2]
147393
# Create the scatter plot
148394
plt.figure()
149-
plt.scatter(column_1, column_3, s=5, c='red')
395+
plt.scatter(data[:, 0], data[:, 2], s=5, c='red')
150396
# Set labels and title
151397
plt.xlabel('Level (m)')
152398
plt.ylabel('Storage (mcm)')
153399
plt.title(res_name)
154400
plt.savefig(res_name+'_storageVSelevation.png', dpi=600, bbox_inches='tight')
155401

156402
return min_dem
403+
404+
405+
#=================================== Update Landsat-based E-A database with DEM-based E-A-S relationship
406+
def one_tile(res_name, max_wl, dead_wl, res_directory):
407+
408+
os.chdir(res_directory + "/Outputs")
409+
curve = pd.read_csv('Curve_' + res_name + '.csv')
410+
landsat_wsa = pd.read_csv('WSA_' + res_name + '.csv')
411+
412+
Wsa= landsat_wsa
413+
Wsa["dem_value_m"] = None
414+
Wsa["Tot_res_volume_mcm"] = None
415+
for i in range(0,len(Wsa)):
416+
diff = np.abs(curve.iloc[:, 1] - Wsa.Fn_area[i])
417+
closest_index = np.argmin(diff)
418+
closest_elev = curve.iloc[closest_index, 0]
419+
closest_vol = curve.iloc[closest_index, 2]
420+
Wsa.dem_value_m[i] = closest_elev
421+
Wsa.Tot_res_volume_mcm[i] = closest_vol
422+
423+
delete_id = Wsa[(Wsa['Quality'] == 0) | (Wsa['dem_value_m'] < dead_wl) | (Wsa['dem_value_m'] > max_wl+20)].index
424+
Wsa = Wsa.drop(delete_id)
425+
# ========================================== EXPORT RESULTS AS A CSV FILE
426+
Wsa.to_csv('WSA_updated_' + res_name + '.csv', index=False)
427+
print("Done")
428+
print(" ")
157429

158430

159431

0 commit comments

Comments
 (0)