AJMR-Python-Baird/LSU_D3D/LSU_PlotD3D_GeoTIFF.py

527 lines
21 KiB
Python

#%% Plotting script for LSU D3D data
# Alexander Rey, 2022
import os
import pandas as pd
import geopandas as gp
import netCDF4 as nc
import math
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.cm as cm
import datetime as datetime
from scipy.interpolate import LinearNDInterpolator, interp1d
from dfm_tools.get_nc import get_netdata, get_ncmodeldata, plot_netmapdata
from dfm_tools.get_nc_helpers import get_timesfromnc, get_ncfilelist, get_hisstationlist, get_ncvardimlist, get_timesfromnc
import cartopy.crs as ccrs
import contextily as ctx
from dfm_tools.regulargrid import scatter_to_regulargrid
import pathlib as pl
from shapely.geometry import Point, MultiPoint
import alphashape
import rasterio
from rasterio.plot import show as rioshow
from osgeo import osr #Spatial reference module
#%% Read Model Log
pth = pl.Path("//srv-mad3.baird.com/", "Projects", "13522.101 LSU Lakes", "06_Models", "Delft3DFM", "13522.678.W.SBV.Rev0_LSU Lakes D3D Model Log.xlsx")
runLog = pd.read_excel(pth.as_posix(), "ModelLog")
dataPath = "FlowFM_map.nc"
#%% Import using DFM functions
modelPlot = range(45, 46) #30
# stormTime = [datetime.datetime(2005, 8, 29, 14, 0, 0),
# datetime.datetime(2005, 9, 24, 14, 0, 0),
# datetime.datetime(2005, 12, 28, 14, 0, 0)]
# stormTime = [datetime.datetime(2005, 1, 14, 18, 0, 0),
# datetime.datetime(2005, 2, 3, 18, 0, 0),
# datetime.datetime(2005, 2, 10, 18, 0, 0)]
#stormTime = [datetime.datetime(2005, 12, 31, 18, 0, 0)]
#stormTime = [datetime.datetime(2005, 8, 7, 0, 0, 0)]
ugrid_all = [None] * (max(modelPlot)+1)
X = [None] * (max(modelPlot)+1)
Y = [None] * (max(modelPlot)+1)
U = [None] * (max(modelPlot)+1)
V = [None] * (max(modelPlot)+1)
facex = [None] * (max(modelPlot)+1)
facey = [None] * (max(modelPlot)+1)
ux_mean = [None] * (max(modelPlot)+1)
uy_mean = [None] * (max(modelPlot)+1)
ux = [None] * (max(modelPlot)+1)
uy = [None] * (max(modelPlot)+1)
sed = [None] * (max(modelPlot)+1)
area = [None] * (max(modelPlot)+1)
wd = [None] * (max(modelPlot)+1)
regularMask = [None] * (max(modelPlot)+1)
meshMask = [None] * (max(modelPlot)+1)
alphaPolyList = [None] * (max(modelPlot)+1)
for i in modelPlot:
#file_nc_map = os.path.join(runLog['Run Location'][i], 'FlowFM', 'output', 'FlowFM_map.nc')
file_nc_map = os.path.join(runLog['Run Location'][i], 'FlowFM', 'dflowfm', 'output', 'FlowFM_map.nc')
tSteps = get_timesfromnc(file_nc=file_nc_map, varname='time')
# Find nearest time step to desired time
stormTime = [runLog['End Date'][i]]
tStep = []
for s in stormTime:
abs_deltas_from_target_date = np.absolute(tSteps - s)
tStep.append(np.argmin(abs_deltas_from_target_date))
# tStep = 50
# Get Var info
vars_pd, dims_pd = get_ncvardimlist(file_nc=file_nc_map)
ugrid_all[i] = get_netdata(file_nc=file_nc_map)#,multipart=False)
facex[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_face_x')
facey[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_face_y')
# ux_mean[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_ucxa', timestep=tStep)
# uy_mean[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_ucya', timestep=tStep)
ux[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_ucx',
timestep=tStep, layer='all')
uy[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_ucy',
timestep=tStep, layer='all')
sed[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_bodsed',
timestep=tStep, station='all')
area[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_flowelem_ba')
wd[i] = get_ncmodeldata(file_nc=file_nc_map, varname='mesh2d_waterdepth',
timestep=tStep)
ux_mean[i] = ux[i].mean(axis=2)
uy_mean[i] = uy[i].mean(axis=2)
X[i],Y[i],U[i] = scatter_to_regulargrid(xcoords=facex[i], ycoords=facey[i],
ncellx=50, ncelly=70, values=ux_mean[i][0, :],
maskland_dist=25, method='linear')
X[i],Y[i],V[i] = scatter_to_regulargrid(xcoords=facex[i], ycoords=facey[i],
ncellx=50, ncelly=70, values=uy_mean[i][0, :],
maskland_dist=25, method='linear')
# Find convex hull of pcolor data
# Convert grid to multipoint
# Create a list of grid points
# alphaPoints = list(map(tuple, np.column_stack((facex[i][:], facey[i][:])).data))
alphaPoints = list(map(tuple, np.column_stack((facex[i][wd[i][0, :] != 0],
facey[i][wd[i][0, :] != 0])).data))
# Find the concave hull
alphaPoly = alphashape.alphashape(alphaPoints, 0.05)
alphaPolyList[i] = alphaPoly
# Create mask of regular grid inside concave hull
regularMask[i] = [alphaPoly.contains(Point(i[0], i[1]))
for i in np.array([X[i].flatten(), Y[i].flatten()]).T]
# Create mask of mesh grid points inside concave hull
meshMask[i] = [alphaPoly.contains(Point(i[0], i[1]))
for i in np.array([facex[i], facey[i]]).T]
# Reshape back to regular grid for mask
regularMask[i] = np.array(regularMask[i]).reshape(X[i].shape)
#%% Plot using DFM functions
modelPlot = [24]
# stormDirs = [306, 135, 250]
stormDirs = [3, 346, 342]
# fig, axes = plt.subplots(nrows=1, ncols=3,subplot_kw={'projection': ccrs.epsg(26915)}, figsize=(13, 6))
fig, axes = plt.subplots(nrows=1, ncols=2, subplot_kw={'projection': ccrs.epsg(26915)}, figsize=(10, 6))
fig.patch.set_facecolor('white')
plt.tight_layout()
plotCount = 1
vmin = 0 # Legend min
vmax = 0.05 # Legend max
scale = 60 # Size of arrows, smaller is bigger #40 # 15
qmax = 0.025 # Scaling threshold. Above this value, arrows are scaled to 1 #0.1
amin = 1 # Minimum arrow length. A dot is used below this value
for tPlot in range(1, 2):
for i in modelPlot:
vel_mask = meshMask[i]
pc = plot_netmapdata(ugrid_all[i].verts[vel_mask],
values=np.sqrt(ux_mean[i][tPlot, :][vel_mask]**2 +\
uy_mean[i][tPlot, :][vel_mask]**2),
ax=axes[plotCount], linewidth=0.5, cmap="viridis")
axes[plotCount].set_xlim(675524, 677027)
axes[plotCount].set_ylim(3365191, 3367182)
# axes[plotCount].set_xlim(676470, 677021)
# axes[plotCount].set_ylim(3365939, 3366617)
# axes.quiver(X[i], Y[i], U[i], V[i], color='w', scale=8)
# Normalize velocity above limit
# Using fixed grid
overGrid_U_Scale = U[i]
overGrid_V_Scale = V[i]
# Using model grid
# overGrid_U_Scale = ux_mean[i][tPlot, :]
# overGrid_V_Scale = uy_mean[i][tPlot, :]
r = np.power(np.add(np.power(overGrid_U_Scale, 2), np.power(overGrid_V_Scale, 2)), 0.5)
curPlotMask = np.sqrt((overGrid_U_Scale) ** 2 + (overGrid_V_Scale) ** 2) > qmax
overGrid_U_Plot = np.zeros(overGrid_U_Scale.shape)
overGrid_V_Plot = np.zeros(overGrid_V_Scale.shape)
# Normalize arrows to 1 where not zero
overGrid_U_Plot[r != 0] = overGrid_U_Scale[r != 0] / r[r != 0]
overGrid_V_Plot[r != 0] = overGrid_V_Scale[r != 0] / r[r != 0]
# Scale arrows below qmax
overGrid_U_Plot[~curPlotMask] = overGrid_U_Plot[~curPlotMask] * (r[~curPlotMask] / qmax)
overGrid_V_Plot[~curPlotMask] = overGrid_V_Plot[~curPlotMask] * (r[~curPlotMask] / qmax)
# Using fixed grid
# Remove arrows outside of convex hull
overGrid_U_Plot[~regularMask[i]] = np.nan
overGrid_V_Plot[~regularMask[i]] = np.nan
qv = axes[plotCount].quiver(X[i], Y[i], overGrid_U_Plot, overGrid_V_Plot, scale=scale,
color='k', headlength=3.5, headwidth=3.5, headaxislength=3.5, width=0.0015, minlength=amin) #200
# # Using model grid
# # Remove arrows outside convex hull
# overGrid_U_Plot[~np.array(meshMask[i])] = np.nan
# overGrid_V_Plot[~np.array(meshMask[i])] = np.nan
# qv = axes[plotCount].quiver(facex[i], facey[i], overGrid_U_Plot, overGrid_V_Plot, scale=scale,
# color='k', headlength=3.5, headwidth=3.5, headaxislength=3.5, width=0.0015, minlength=amin) #200
mapbox = 'https://api.mapbox.com/styles/v1/alexander0042/ckemxgtk51fgp19nybfmdcb1e/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoiYWxleGFuZGVyMDA0MiIsImEiOiJjazVmdG4zbncwMHY4M2VrcThwZGUzZDFhIn0.w6oDHoo1eCeRlSBpwzwVtw'
ctx.add_basemap(axes[plotCount], source=mapbox, crs='EPSG:26915')
# extent = ax[plotCount].get_extent()
# ax[plotCount].set_xticks(np.linspace(extent[0], extent[1], 4))
# ax[plotCount].set_yticks(np.linspace(extent[2], extent[3], 4))
# Add model bounds line
axes[plotCount].plot(*alphaPoly.exterior.xy, color='k', linewidth=1)
pc.set_clim([vmin, vmax])
if plotCount == 1:
cbar = fig.colorbar(pc, ax=axes, shrink=0.95)
cbar.set_label('Depth Averaged Velocity [m/s]')
axes[plotCount].set_title('Wind Direction: ' + str(stormDirs[tPlot]) + ' Degrees')
# Add rectangle to show storm arrow
xLimDist = axes[plotCount].get_xlim()[1] - axes[plotCount].get_xlim()[0]
yLimDist = axes[plotCount].get_ylim()[1] - axes[plotCount].get_ylim()[0]
axes[plotCount].add_patch(patches.Rectangle((axes[plotCount].get_xlim()[0] + 0.7 * xLimDist,
axes[plotCount].get_ylim()[0] + 0.8 * yLimDist - xLimDist * 0.1),
xLimDist * 0.2, xLimDist * 0.2,
facecolor='white', edgecolor='w', linewidth=5))
# Add wind arrow
# Set at 80% of axis limits
axes[plotCount].arrow(axes[plotCount].get_xlim()[0] + 0.8 * xLimDist,
axes[plotCount].get_ylim()[0] + 0.8 * yLimDist,
xLimDist * 0.03 * math.sin(math.radians(stormDirs[tPlot])),
xLimDist * 0.03 * math.cos(math.radians(stormDirs[tPlot])),
width=xLimDist * 0.015,
color='k')
plotCount = plotCount + 1
plt.show()
fig.savefig(
'C:/Users/arey/files/Projects/LSU/Modelling/Figures/' +
'StormVelDisWide.png', bbox_inches='tight', dpi=400)
# %% Setup forebay polygon
# forebayPoly = gp.read_file('C:/Users/arey/files/Projects/LSU/ForebayPoly.shp')
forebayPoly = gp.read_file('C:/Users/arey/files/Projects/LSU/ForebayPolyExpand.shp')
# Setup mask. Can only do this once if grids are the same
i = 45
forebayPolyMask = [forebayPoly.iloc[0, 1].contains(Point(i[0], i[1]))
for i in np.array([facex[i], facey[i]]).T]
# %% Read in hist file
#
modelPlot = range(45, 46)
cumSedCS = [None] * (max(modelPlot)+1)
cumSedCS_B = [None] * (max(modelPlot)+1)
SedCS_B = [None] * (max(modelPlot)+1)
cs_Names = [None] * (max(modelPlot)+1)
cumDis = [None] * (max(modelPlot)+1)
cumDisVol = [None] * (max(modelPlot)+1)
for i in modelPlot:
file_nc_hist = os.path.join(runLog['Run Location'][i], 'FlowFM', 'dflowfm', 'output', 'FlowFM_his.nc')
# Get Var info
vars_pd, dims_pd = get_ncvardimlist(file_nc=file_nc_hist)
# cumSedCS[i] = get_ncmodeldata(file_nc=file_nc_hist, varname='cross_section_cumulative_Sediment',
# timestep='all', station='all')
# SedCS_B[i] = get_ncmodeldata(file_nc=file_nc_hist, varname='cross_section_suspended_sediment_transport',
# timestep='all', station='all')
# cumSedCS_B[i] = SedCS_B[i].cumsum(axis=1)
#
# cs_Names[i] = get_ncmodeldata(file_nc=file_nc_hist, varname='cross_section_name',
# station='all')
cumDis[i] = get_ncmodeldata(file_nc=file_nc_hist, varname='source_sink_prescribed_discharge',
timestep='all', station='all')
cumDisVol[i] = cumDis[i] * 5 * 60 * 129.6
cumDisVol[i] = cumDisVol[i].sum()
# Get Time info
# tStepsHist = get_timesfromnc(file_nc=file_nc_hist, varname='time')
#%% Plot Sediment DFM functions
# modelPlot = [30, 31, 32, 33, 34, 35]
#modelPlot = [30, 35]
# modelPlot = [35]
# stormDirs = [306, 135, 250]
modelPlot = range(45, 46)
# fig, axes = plt.subplots(nrows=1, ncols=3,subplot_kw={'projection': ccrs.epsg(26915)}, figsize=(13, 6))
# fig, axes = plt.subplots(nrows=1, ncols=3,
# subplot_kw={'projection': ccrs.epsg(26915)},
# figsize=(6, 6))
# fig.patch.set_facecolor('white')
# plt.tight_layout()
plotCount = 1
sedIDX = 0
Trapping_List = [None] * (max(modelPlot)+1)
for tPlot in range(0, 1):
for i in modelPlot:
# Plot as seperate figures
fig, axes = plt.subplots(nrows=1, ncols=1,
subplot_kw={'projection': ccrs.epsg(26915)},
figsize=(6, 6))
fig.patch.set_facecolor('white')
vel_mask = meshMask[i]
pc = plot_netmapdata(ugrid_all[i].verts[vel_mask],
values=sed[i][tPlot, :, sedIDX][vel_mask],
ax=axes, linewidth=0.5,
cmap="viridis")
# pc = plot_netmapdata(ugrid_all[i].verts[vel_mask],
# values=area[i][:][vel_mask],
# ax=axes, linewidth=0.5,
# cmap="viridis")
# axes[plotCount].set_xlim(675524, 677027)
# axes[plotCount].set_ylim(3365191, 3367182)
axes.set_xlim(676470, 677021)
axes.set_ylim(3365939, 3366617)
mapbox = 'https://api.mapbox.com/styles/v1/alexander0042/ckemxgtk51fgp19nybfmdcb1e/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoiYWxleGFuZGVyMDA0MiIsImEiOiJjazVmdG4zbncwMHY4M2VrcThwZGUzZDFhIn0.w6oDHoo1eCeRlSBpwzwVtw'
ctx.add_basemap(axes, source=mapbox, crs='EPSG:26915')
# extent = ax[plotCount].get_extent()
# ax[plotCount].set_xticks(np.linspace(extent[0], extent[1], 4))
# ax[plotCount].set_yticks(np.linspace(extent[2], extent[3], 4))
# Add model bounds line
alphaPoly = alphaPolyList[i]
axes.plot(*alphaPoly.exterior.xy, color='k', linewidth=1)
# Add forebay bounds line
forebayPoly.plot(ax=axes, linewidth=2,
facecolor='none', edgecolor='r')
if i in [44, 45, 36, 37]:
pc.set_clim([0, 2000])
else:
pc.set_clim([0, 200])
cbar = fig.colorbar(pc, ax=axes, shrink=0.95)
cbar.set_label('Available mass of sediment [$kg/m^2$]')
# Calculate sediment in polygon
massSed = sed[i][0, :, 0] * area[i]
massSedSum = np.sum(massSed)
massSed_FB = sed[i][0, forebayPolyMask, 0]\
* area[i][forebayPolyMask]
massSedSum_FB = np.sum(massSed_FB)
# Add title
# axes.set_title('Existing Condition: ' + "{:0.1f}".format(
# (massSedSum_FB / massSedSum) * 100) + '% Trapping')
# axes.set_title(runLog['Short Description'][i] + ': ' + "{:0.1f}".format(
# (massSedSum_FB / massSedSum) * 100) + '% Trapping')
plt.title(runLog['Short Description'][i] + ": {:0.1f}".format(
(massSedSum_FB / cumDisVol[i]) * 100) + '% Trapping')
plt.tight_layout()
Trapping_List[i] = (massSedSum_FB / cumDisVol[i])
# # Add rectangle to show storm arrow
# xLimDist = axes.get_xlim()[1] - axes.get_xlim()[0]
# yLimDist = axes.get_ylim()[1] - axes.get_ylim()[0]
#
# axes.add_patch(patches.Rectangle((axes.get_xlim()[0] + 0.7 * xLimDist,
# axes.get_ylim()[0] + 0.8 * yLimDist - xLimDist * 0.1),
# xLimDist * 0.2, xLimDist * 0.2,
# facecolor='white', edgecolor='w', linewidth=5))
#
#
# # Add wind arrow
# # Set at 80% of axis limits
# axes.arrow(axes.get_xlim()[0] + 0.8 * xLimDist,
# axes.get_ylim()[0] + 0.8 * yLimDist,
# xLimDist * 0.03 * math.sin(math.radians(stormDirs[tPlot])),
# xLimDist * 0.03 * math.cos(math.radians(stormDirs[tPlot])),
# width=xLimDist * 0.015,
# color='k')
plotCount = plotCount + 1
plt.show()
# fig.savefig(
# 'C:/Users/arey/files/Projects/LSU/Modelling/FiguresExpand/' +
# runLog['Run Name'][i] + '.png', bbox_inches='tight', dpi=400)
# plt.show()
# fig.savefig(
# 'C:/Users/arey/files/Projects/LSU/Modelling/Figures/' +
# 'SedZoomPercent.png', bbox_inches='tight', dpi=400)
# %% Create summary table
modelPlot = range(30, 46)
trappingSumTable = pd.DataFrame()
trappingSumTable['Description'] = runLog['Short Description'][modelPlot]
trappingSumTable['Trapping'] = np.array(Trapping_List)[modelPlot]
# %% Calculate the total sediment discharged
fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(6,6))
modelPlot = [27]
sourceSinkDat = []
for i in modelPlot:
for sourceSink in range(1, 5):
# Read in the sediment discharge file (.tim)
sourceSinkFile = os.path.join(runLog['Run Location'][i], 'FlowFM', 'input', 'SourceSink0' + str(sourceSink) + '.tim')
sourceSinkDat.append(pd.read_csv(sourceSinkFile, sep='\s+', header=None, names=['time', 'Q', 'conc_sed', 'conc_fluff']))
# Add datetimes
sourceSinkDat[-1].index = pd.to_datetime(sourceSinkDat[-1].time, unit='m', origin=pd.Timestamp('2005-01-01'))
# Vol sediment at each time step, multiplied by the time step
sourceSinkDat[-1]['SedVol'] = sourceSinkDat[-1]['Q'] *\
sourceSinkDat[-1].loc[:, 'time'].diff() * 60 *\
sourceSinkDat[-1]['conc_sed']
# Fix first time step
sourceSinkDat[-1].iloc[0, -1] = 0
# Sediment cumlative sum
sourceSinkDat[-1].loc[:, 'CumSed'] = sourceSinkDat[-1].loc[:, 'SedVol'].cumsum()
sourceSinkDat[-1].loc[:, 'Q'].rolling(24*4).sum().plot()
plt.show()
# %% Read in 15 minute precipitation data
prep_data = pd.read_excel('//srv-mad3/Projects/13522.101 LSU Lakes/06_Models/PCSWMM Model/DataforHistoricRuns/15min_precip_formatted.xlsx',
sheet_name='Sheet2')
prep_data['DateTime'] = pd.to_datetime(prep_data['DT'])
prep_data.set_index('DateTime', inplace=True)
# %% Plot 24h precipitationto find events
fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(12, 6))
prep_data.loc[:, 'per 15min'].rolling(24 * 4).sum().plot()
axes.set_ylabel('24h Precipiation (in)')
axes.set_xlim((pd.to_datetime('20050701'), pd.to_datetime('20060101')))
plt.show()
# fig.savefig(('//srv-mad3/Projects/13522.101 LSU Lakes/06_Models/PCSWMM Model/DataforHistoricRuns/24h_PrecpSum.png')
# %% Plot the sediment discharge and cumlative transport
fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(6,6))
csIDX = 3
# Calculate the total sediment discharged
# SS 1/2 is SouthWest, 3/4 is SouthEast
sourceSinkDat[0].loc[:, 'CumSed'].multiply(2).plot(
label='Discharged Sediment SW') # in kg
sourceSinkDat[2].loc[:, 'CumSed'].multiply(2).plot(
label='Discharged Sediment NE') # in kg
totalSedDis = sourceSinkDat[0].loc[:, 'CumSed'].multiply(2) +\
sourceSinkDat[2].loc[:, 'CumSed'].multiply(2)
# Plot the total sediment discharge
totalSedDis.plot(label='Total Discharged Sediment')
axes.plot(tStepsHist, cumSedCS[i][:, csIDX]*2650,
label='Cross Section Sediment Transport', color='k') # In M3. Multiple by 2650 to get kg
# axes.plot(tStepsHist, cumSedCS_B[i][:, csIDX],
# label='Cross Section Sediment Transport B', color='r') # In M3. Multiple by 2650 to get kg
axes.set_xlabel('Date')
axes.set_ylabel('Sediment [kg]')
trappedSed = (1 - (cumSedCS[i][-1, csIDX]*2650) /
totalSedDis[-1])*100
trappedSedB = (1 - (cumSedCS_B[i][-1, csIDX]) /
totalSedDis[-1])*100
axes.set_title('Sediment Transport: ' + "{:0.1f}".format(trappedSed) + '% Trapping')
plt.legend()
plt.show()
# fig.savefig(
# 'C:/Users/arey/files/Projects/LSU/Modelling/Figures/' +
# 'SedTrap_Concept_NE.png', bbox_inches='tight', dpi=400)
# fig.savefig(
# 'C:/Users/arey/files/Projects/LSU/Modelling/Figures/' +
# 'SedTrap_Concept.png', bbox_inches='tight', dpi=400)