|
|
|
@ -4,6 +4,7 @@ import pandas as pd
|
|
|
|
|
from scipy.integrate import simps
|
|
|
|
|
|
|
|
|
|
from logs import setup_logging
|
|
|
|
|
from utils import crossings
|
|
|
|
|
|
|
|
|
|
logger = setup_logging()
|
|
|
|
|
|
|
|
|
@ -41,14 +42,9 @@ def volume_change(df_profiles, df_profile_features, zone):
|
|
|
|
|
"Calculating change in beach volume at {} in {} zone".format(site_id, zone)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# TODO Change this query to an index
|
|
|
|
|
query = "site_id=='{}'&profile_type=='prestorm'".format(site_id)
|
|
|
|
|
prestorm_dune_toe_x = df_profile_features.query(query).dune_toe_x.tolist()
|
|
|
|
|
prestorm_dune_crest_x = df_profile_features.query(query).dune_crest_x.tolist()
|
|
|
|
|
|
|
|
|
|
# We may not have a dune toe or crest defined, or there may be multiple defined.
|
|
|
|
|
prestorm_dune_crest_x = return_first_or_nan(prestorm_dune_crest_x)
|
|
|
|
|
prestorm_dune_toe_x = return_first_or_nan(prestorm_dune_toe_x)
|
|
|
|
|
prestorm_row = df_profile_features.loc[(site_id, "prestorm")]
|
|
|
|
|
prestorm_dune_toe_x = prestorm_row.dune_toe_x
|
|
|
|
|
prestorm_dune_crest_x = prestorm_row.dune_crest_x
|
|
|
|
|
|
|
|
|
|
# If no dune toe has been defined, Dlow = Dhigh. Refer to Sallenger (2000).
|
|
|
|
|
if np.isnan(prestorm_dune_toe_x):
|
|
|
|
@ -56,8 +52,7 @@ def volume_change(df_profiles, df_profile_features, zone):
|
|
|
|
|
|
|
|
|
|
# If no prestorm and poststorm profiles, skip site and continue
|
|
|
|
|
profile_lengths = [
|
|
|
|
|
len(df_site.query("profile_type == '{}'".format(x)))
|
|
|
|
|
for x in ["prestorm", "poststorm"]
|
|
|
|
|
len(df_site.xs(x, level="profile_type")) for x in ["prestorm", "poststorm"]
|
|
|
|
|
]
|
|
|
|
|
if any([length == 0 for length in profile_lengths]):
|
|
|
|
|
continue
|
|
|
|
@ -113,20 +108,52 @@ def volume_change(df_profiles, df_profile_features, zone):
|
|
|
|
|
x_max=x_max,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Volume change needs to be calculated including a tolerance for LIDAR accuracy. If difference between
|
|
|
|
|
# profiles is less than 20 cm, consider them as zero difference.
|
|
|
|
|
prestorm_z = (
|
|
|
|
|
df_zone.query("profile_type=='prestorm'").reset_index("profile_type").z
|
|
|
|
|
# Identify the x location where our pre and post storm profiles start to differ. This is so changes no due to
|
|
|
|
|
# the storm are not included when calculating volume.
|
|
|
|
|
df_prestorm = (
|
|
|
|
|
df_site.xs("prestorm", level="profile_type").z.rename("z_pre").to_frame()
|
|
|
|
|
)
|
|
|
|
|
poststorm_z = (
|
|
|
|
|
df_zone.query("profile_type=='poststorm'").reset_index("profile_type").z
|
|
|
|
|
df_poststorm = (
|
|
|
|
|
df_site.xs("poststorm", level="profile_type").z.rename("z_post").to_frame()
|
|
|
|
|
)
|
|
|
|
|
diff_z = prestorm_z - poststorm_z
|
|
|
|
|
diff_z[abs(diff_z) < 0.2] = 0
|
|
|
|
|
df_diff = df_prestorm.merge(df_poststorm, on=["site_id", "x"])
|
|
|
|
|
df_diff["z_diff"] = df_diff.z_pre - df_diff.z_post
|
|
|
|
|
|
|
|
|
|
# Find all locations where the difference in pre and post storm is zero. Take the most seaward location as the
|
|
|
|
|
# x location where our profiles are the same.
|
|
|
|
|
x_crossings = crossings(df_diff.index.get_level_values("x"), df_diff.z_diff, 0)
|
|
|
|
|
|
|
|
|
|
if len(x_crossings) != 0:
|
|
|
|
|
x_change_point = x_crossings[-1]
|
|
|
|
|
else:
|
|
|
|
|
x_change_point = np.nan
|
|
|
|
|
|
|
|
|
|
# # For debugging
|
|
|
|
|
# import matplotlib.pyplot as plt
|
|
|
|
|
# f,(ax1,ax2) = plt.subplots(2,1,sharex=True)
|
|
|
|
|
# ax1.plot(df_prestorm.index.get_level_values('x'), df_prestorm.z_pre,label='prestorm')
|
|
|
|
|
# ax1.plot(df_poststorm.index.get_level_values('x'), df_poststorm.z_post,label='poststorm')
|
|
|
|
|
# ax1.axvline(x_crossings[-1], color='red', linestyle='--', linewidth=0.5, label='Change point')
|
|
|
|
|
# ax1.legend()
|
|
|
|
|
# ax1.set_title(site_id)
|
|
|
|
|
# ax1.set_ylabel('elevation (m AHD)')
|
|
|
|
|
# ax2.plot(df_diff.index.get_level_values('x'), df_diff.z_diff)
|
|
|
|
|
# ax2.set_xlabel('x coordinate (m)')
|
|
|
|
|
# ax2.set_ylabel('elevation diff (m)')
|
|
|
|
|
# ax2.axvline(x_crossings[-1],color='red',linestyle='--',linewidth=0.5)
|
|
|
|
|
# plt.show()
|
|
|
|
|
|
|
|
|
|
diff_vol = beach_volume(
|
|
|
|
|
x=diff_z.index.get_level_values("x"), z=diff_z, x_min=x_min, x_max=x_max
|
|
|
|
|
x=df_diff.index.get_level_values("x"),
|
|
|
|
|
z=df_diff.z_diff,
|
|
|
|
|
x_min=np.nanmax([x_min, x_change_point]),
|
|
|
|
|
x_max=np.nanmax([x_max, x_change_point]),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Here, if cannot calculate the difference volume, assume no volume change
|
|
|
|
|
if np.isnan(diff_vol):
|
|
|
|
|
diff_vol = 0
|
|
|
|
|
|
|
|
|
|
df_vol_changes.loc[site_id, "prestorm_{}_vol".format(zone)] = prestorm_vol
|
|
|
|
|
df_vol_changes.loc[site_id, "poststorm_{}_vol".format(zone)] = poststorm_vol
|
|
|
|
|
df_vol_changes.loc[site_id, "{}_vol_change".format(zone)] = diff_vol
|
|
|
|
|