|
|
@ -9,54 +9,57 @@ from scipy import stats
|
|
|
|
|
|
|
|
|
|
|
|
from src.analysis.runup_models import sto06_individual, sto06
|
|
|
|
from src.analysis.runup_models import sto06_individual, sto06
|
|
|
|
|
|
|
|
|
|
|
|
logging.config.fileConfig('./src/logging.conf', disable_existing_loggers=False)
|
|
|
|
logging.config.fileConfig("./src/logging.conf", disable_existing_loggers=False)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def forecast_twl(df_tides, df_profiles, df_waves, df_profile_features, runup_function, n_processes=4,
|
|
|
|
def forecast_twl(
|
|
|
|
slope='foreshore'):
|
|
|
|
df_tides, df_profiles, df_waves, df_profile_features, runup_function, n_processes=4, slope="foreshore"
|
|
|
|
|
|
|
|
):
|
|
|
|
# Use df_waves as a base
|
|
|
|
# Use df_waves as a base
|
|
|
|
df_twl = df_waves.copy()
|
|
|
|
df_twl = df_waves.copy()
|
|
|
|
|
|
|
|
|
|
|
|
# Merge tides
|
|
|
|
# Merge tides
|
|
|
|
logger.info('Merging tides')
|
|
|
|
logger.info("Merging tides")
|
|
|
|
df_twl = df_twl.merge(df_tides, left_index=True, right_index=True)
|
|
|
|
df_twl = df_twl.merge(df_tides, left_index=True, right_index=True)
|
|
|
|
|
|
|
|
|
|
|
|
# Estimate foreshore slope. Do the analysis per site_id. This is so we only have to query the x and z
|
|
|
|
# Estimate foreshore slope. Do the analysis per site_id. This is so we only have to query the x and z
|
|
|
|
# cross-section profiles once per site.
|
|
|
|
# cross-section profiles once per site.
|
|
|
|
logger.info('Calculating beach slopes')
|
|
|
|
logger.info("Calculating beach slopes")
|
|
|
|
site_ids = df_twl.index.get_level_values('site_id').unique()
|
|
|
|
site_ids = df_twl.index.get_level_values("site_id").unique()
|
|
|
|
# site_ids = [x for x in site_ids if 'NARRA' in x] # todo remove this - for testing narrabeen only
|
|
|
|
# site_ids = [x for x in site_ids if 'NARRA' in x] # todo remove this - for testing narrabeen only
|
|
|
|
|
|
|
|
|
|
|
|
if slope == 'foreshore':
|
|
|
|
if slope == "foreshore":
|
|
|
|
# Process each site_id with a different process and combine results at the end
|
|
|
|
# Process each site_id with a different process and combine results at the end
|
|
|
|
with Pool(processes=n_processes) as pool:
|
|
|
|
with Pool(processes=n_processes) as pool:
|
|
|
|
results = pool.starmap(foreshore_slope_for_site_id,
|
|
|
|
results = pool.starmap(
|
|
|
|
[(site_id, df_twl, df_profiles) for site_id in site_ids])
|
|
|
|
foreshore_slope_for_site_id, [(site_id, df_twl, df_profiles) for site_id in site_ids]
|
|
|
|
df_twl['beta'] = pd.concat(results)
|
|
|
|
)
|
|
|
|
|
|
|
|
df_twl["beta"] = pd.concat(results)
|
|
|
|
|
|
|
|
|
|
|
|
elif slope == 'mean':
|
|
|
|
elif slope == "mean":
|
|
|
|
# todo mean beach profile
|
|
|
|
# todo mean beach profile
|
|
|
|
df_temp = df_twl.join(df_profile_features, how='inner')
|
|
|
|
df_temp = df_twl.join(df_profile_features, how="inner")
|
|
|
|
df_temp['mhw'] = 0.5
|
|
|
|
df_temp["mhw"] = 0.5
|
|
|
|
with Pool(processes=n_processes) as pool:
|
|
|
|
with Pool(processes=n_processes) as pool:
|
|
|
|
results = pool.starmap(mean_slope_for_site_id,
|
|
|
|
results = pool.starmap(
|
|
|
|
[(site_id, df_temp, df_profiles, 'dune_toe_z', 'mhw') for site_id in site_ids])
|
|
|
|
mean_slope_for_site_id, [(site_id, df_temp, df_profiles, "dune_toe_z", "mhw") for site_id in site_ids]
|
|
|
|
df_twl['beta'] = pd.concat(results)
|
|
|
|
)
|
|
|
|
|
|
|
|
df_twl["beta"] = pd.concat(results)
|
|
|
|
|
|
|
|
|
|
|
|
# Estimate runup
|
|
|
|
# Estimate runup
|
|
|
|
R2, setup, S_total, S_inc, S_ig = runup_function(df_twl, Hs0_col='Hs0', Tp_col='Tp', beta_col='beta')
|
|
|
|
R2, setup, S_total, S_inc, S_ig = runup_function(df_twl, Hs0_col="Hs0", Tp_col="Tp", beta_col="beta")
|
|
|
|
|
|
|
|
|
|
|
|
df_twl['R2'] = R2
|
|
|
|
df_twl["R2"] = R2
|
|
|
|
df_twl['setup'] = setup
|
|
|
|
df_twl["setup"] = setup
|
|
|
|
df_twl['S_total'] = S_total
|
|
|
|
df_twl["S_total"] = S_total
|
|
|
|
|
|
|
|
|
|
|
|
# Estimate TWL
|
|
|
|
# Estimate TWL
|
|
|
|
df_twl['R_high'] = df_twl['tide'] + df_twl['R2']
|
|
|
|
df_twl["R_high"] = df_twl["tide"] + df_twl["R2"]
|
|
|
|
df_twl['R_low'] = df_twl['tide'] + 1.1 * df_twl['setup'] - 1.1 / 2 * df_twl['S_total']
|
|
|
|
df_twl["R_low"] = df_twl["tide"] + 1.1 * df_twl["setup"] - 1.1 / 2 * df_twl["S_total"]
|
|
|
|
|
|
|
|
|
|
|
|
# Drop unneeded columns
|
|
|
|
# Drop unneeded columns
|
|
|
|
df_twl.drop(columns=['E', 'Exs', 'P', 'Pxs', 'dir'], inplace=True, errors='ignore')
|
|
|
|
df_twl.drop(columns=["E", "Exs", "P", "Pxs", "dir"], inplace=True, errors="ignore")
|
|
|
|
|
|
|
|
|
|
|
|
return df_twl
|
|
|
|
return df_twl
|
|
|
|
|
|
|
|
|
|
|
@ -74,15 +77,21 @@ def mean_slope_for_site_id(site_id, df_twl, df_profiles, top_elevation_col, btm_
|
|
|
|
|
|
|
|
|
|
|
|
# Get the prestorm beach profile
|
|
|
|
# Get the prestorm beach profile
|
|
|
|
profile = df_profiles.query("site_id =='{}' and profile_type == 'prestorm'".format(site_id))
|
|
|
|
profile = df_profiles.query("site_id =='{}' and profile_type == 'prestorm'".format(site_id))
|
|
|
|
profile_x = profile.index.get_level_values('x').tolist()
|
|
|
|
profile_x = profile.index.get_level_values("x").tolist()
|
|
|
|
profile_z = profile.z.tolist()
|
|
|
|
profile_z = profile.z.tolist()
|
|
|
|
|
|
|
|
|
|
|
|
df_twl_site = df_twl.query("site_id == '{}'".format(site_id))
|
|
|
|
df_twl_site = df_twl.query("site_id == '{}'".format(site_id))
|
|
|
|
|
|
|
|
|
|
|
|
df_beta = df_twl_site.apply(lambda row: slope_from_profile(profile_x=profile_x, profile_z=profile_z,
|
|
|
|
df_beta = df_twl_site.apply(
|
|
|
|
|
|
|
|
lambda row: slope_from_profile(
|
|
|
|
|
|
|
|
profile_x=profile_x,
|
|
|
|
|
|
|
|
profile_z=profile_z,
|
|
|
|
top_elevation=row[top_elevation_col],
|
|
|
|
top_elevation=row[top_elevation_col],
|
|
|
|
btm_elevation=row[btm_elevation_col],
|
|
|
|
btm_elevation=row[btm_elevation_col],
|
|
|
|
method='end_points'), axis=1)
|
|
|
|
method="end_points",
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
axis=1,
|
|
|
|
|
|
|
|
)
|
|
|
|
return df_beta
|
|
|
|
return df_beta
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -99,16 +108,22 @@ def foreshore_slope_for_site_id(site_id, df_twl, df_profiles):
|
|
|
|
|
|
|
|
|
|
|
|
# Get the prestorm beach profile
|
|
|
|
# Get the prestorm beach profile
|
|
|
|
profile = df_profiles.query("site_id =='{}' and profile_type == 'prestorm'".format(site_id))
|
|
|
|
profile = df_profiles.query("site_id =='{}' and profile_type == 'prestorm'".format(site_id))
|
|
|
|
profile_x = profile.index.get_level_values('x').tolist()
|
|
|
|
profile_x = profile.index.get_level_values("x").tolist()
|
|
|
|
profile_z = profile.z.tolist()
|
|
|
|
profile_z = profile.z.tolist()
|
|
|
|
|
|
|
|
|
|
|
|
df_twl_site = df_twl.query("site_id == '{}'".format(site_id))
|
|
|
|
df_twl_site = df_twl.query("site_id == '{}'".format(site_id))
|
|
|
|
|
|
|
|
|
|
|
|
df_beta = df_twl_site.apply(lambda row: foreshore_slope_from_profile(profile_x=profile_x, profile_z=profile_z,
|
|
|
|
df_beta = df_twl_site.apply(
|
|
|
|
|
|
|
|
lambda row: foreshore_slope_from_profile(
|
|
|
|
|
|
|
|
profile_x=profile_x,
|
|
|
|
|
|
|
|
profile_z=profile_z,
|
|
|
|
tide=row.tide,
|
|
|
|
tide=row.tide,
|
|
|
|
runup_function=sto06_individual,
|
|
|
|
runup_function=sto06_individual,
|
|
|
|
Hs0=row.Hs0,
|
|
|
|
Hs0=row.Hs0,
|
|
|
|
Tp=row.Tp), axis=1)
|
|
|
|
Tp=row.Tp,
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
axis=1,
|
|
|
|
|
|
|
|
)
|
|
|
|
return df_beta
|
|
|
|
return df_beta
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -137,9 +152,13 @@ def foreshore_slope_from_profile(profile_x, profile_z, tide, runup_function, **k
|
|
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
while True:
|
|
|
|
R2, setup, S_total, _, _ = runup_function(beta=beta, **kwargs)
|
|
|
|
R2, setup, S_total, _, _ = runup_function(beta=beta, **kwargs)
|
|
|
|
beta_new = slope_from_profile(profile_x=profile_x, profile_z=profile_z, method='end_points',
|
|
|
|
beta_new = slope_from_profile(
|
|
|
|
|
|
|
|
profile_x=profile_x,
|
|
|
|
|
|
|
|
profile_z=profile_z,
|
|
|
|
|
|
|
|
method="end_points",
|
|
|
|
top_elevation=tide + setup + S_total / 2,
|
|
|
|
top_elevation=tide + setup + S_total / 2,
|
|
|
|
btm_elevation=tide + setup - S_total / 2)
|
|
|
|
btm_elevation=tide + setup - S_total / 2,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Return None if we can't find a slope, usually because the elevations we've specified are above/below our
|
|
|
|
# Return None if we can't find a slope, usually because the elevations we've specified are above/below our
|
|
|
|
# profile x and z coordinates.
|
|
|
|
# profile x and z coordinates.
|
|
|
@ -158,7 +177,7 @@ def foreshore_slope_from_profile(profile_x, profile_z, tide, runup_function, **k
|
|
|
|
iteration_count += 1
|
|
|
|
iteration_count += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, method='end_points'):
|
|
|
|
def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, method="end_points"):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Returns a slope (beta) from a bed profile, given the top and bottom elevations of where the slope should be taken.
|
|
|
|
Returns a slope (beta) from a bed profile, given the top and bottom elevations of where the slope should be taken.
|
|
|
|
:param x: List of x bed profile coordinates
|
|
|
|
:param x: List of x bed profile coordinates
|
|
|
@ -173,16 +192,10 @@ def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, metho
|
|
|
|
if any([x is None for x in [profile_x, profile_z, top_elevation, btm_elevation]]):
|
|
|
|
if any([x is None for x in [profile_x, profile_z, top_elevation, btm_elevation]]):
|
|
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
end_points = {
|
|
|
|
end_points = {"top": {"z": top_elevation}, "btm": {"z": btm_elevation}}
|
|
|
|
'top': {
|
|
|
|
|
|
|
|
'z': top_elevation,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
'btm': {
|
|
|
|
|
|
|
|
'z': btm_elevation,
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for end_type in end_points.keys():
|
|
|
|
for end_type in end_points.keys():
|
|
|
|
elevation = end_points[end_type]['z']
|
|
|
|
elevation = end_points[end_type]["z"]
|
|
|
|
intersection_x = crossings(profile_x, profile_z, elevation)
|
|
|
|
intersection_x = crossings(profile_x, profile_z, elevation)
|
|
|
|
|
|
|
|
|
|
|
|
# No intersections found
|
|
|
|
# No intersections found
|
|
|
@ -191,26 +204,26 @@ def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, metho
|
|
|
|
|
|
|
|
|
|
|
|
# One intersection
|
|
|
|
# One intersection
|
|
|
|
elif len(intersection_x) == 1:
|
|
|
|
elif len(intersection_x) == 1:
|
|
|
|
end_points[end_type]['x'] = intersection_x[0]
|
|
|
|
end_points[end_type]["x"] = intersection_x[0]
|
|
|
|
|
|
|
|
|
|
|
|
# More than on intersection
|
|
|
|
# More than on intersection
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
if end_type == 'top':
|
|
|
|
if end_type == "top":
|
|
|
|
# For top elevation, take most seaward intersection
|
|
|
|
# For top elevation, take most seaward intersection
|
|
|
|
end_points[end_type]['x'] = intersection_x[-1]
|
|
|
|
end_points[end_type]["x"] = intersection_x[-1]
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
# For bottom elevation, take most landward intersection that is seaward of top elevation
|
|
|
|
# For bottom elevation, take most landward intersection that is seaward of top elevation
|
|
|
|
end_points[end_type]['x'] = [x for x in intersection_x if x > end_points['top']['x']][0]
|
|
|
|
end_points[end_type]["x"] = [x for x in intersection_x if x > end_points["top"]["x"]][0]
|
|
|
|
|
|
|
|
|
|
|
|
if method == 'end_points':
|
|
|
|
if method == "end_points":
|
|
|
|
x_top = end_points['top']['x']
|
|
|
|
x_top = end_points["top"]["x"]
|
|
|
|
x_btm = end_points['btm']['x']
|
|
|
|
x_btm = end_points["btm"]["x"]
|
|
|
|
z_top = end_points['top']['z']
|
|
|
|
z_top = end_points["top"]["z"]
|
|
|
|
z_btm = end_points['btm']['z']
|
|
|
|
z_btm = end_points["btm"]["z"]
|
|
|
|
return -(z_top - z_btm) / (x_top - x_btm)
|
|
|
|
return -(z_top - z_btm) / (x_top - x_btm)
|
|
|
|
|
|
|
|
|
|
|
|
elif method == 'least_squares':
|
|
|
|
elif method == "least_squares":
|
|
|
|
profile_mask = [True if end_points['top']['x'] < pts < end_points['btm']['x'] else False for pts in x]
|
|
|
|
profile_mask = [True if end_points["top"]["x"] < pts < end_points["btm"]["x"] else False for pts in x]
|
|
|
|
slope_x = np.array(profile_x)[profile_mask].tolist()
|
|
|
|
slope_x = np.array(profile_x)[profile_mask].tolist()
|
|
|
|
slope_z = np.array(profile_z)[profile_mask].tolist()
|
|
|
|
slope_z = np.array(profile_z)[profile_mask].tolist()
|
|
|
|
slope, _, _, _, _ = stats.linregress(slope_x, slope_z)
|
|
|
|
slope, _, _, _, _ = stats.linregress(slope_x, slope_z)
|
|
|
@ -245,23 +258,25 @@ def crossings(profile_x, profile_z, constant_z):
|
|
|
|
return [profile_x[i] - (profile_x[i] - profile_x[i + 1]) / (z[i] - z[i + 1]) * (z[i]) for i in indicies]
|
|
|
|
return [profile_x[i] - (profile_x[i] - profile_x[i + 1]) / (z[i] - z[i + 1]) * (z[i]) for i in indicies]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
if __name__ == "__main__":
|
|
|
|
logger.info('Importing data')
|
|
|
|
logger.info("Importing data")
|
|
|
|
data_folder = './data/interim'
|
|
|
|
data_folder = "./data/interim"
|
|
|
|
df_waves = pd.read_csv(os.path.join(data_folder, 'waves.csv'), index_col=[0, 1])
|
|
|
|
df_waves = pd.read_csv(os.path.join(data_folder, "waves.csv"), index_col=[0, 1])
|
|
|
|
df_tides = pd.read_csv(os.path.join(data_folder, 'tides.csv'), index_col=[0, 1])
|
|
|
|
df_tides = pd.read_csv(os.path.join(data_folder, "tides.csv"), index_col=[0, 1])
|
|
|
|
df_profiles = pd.read_csv(os.path.join(data_folder, 'profiles.csv'), index_col=[0, 1, 2])
|
|
|
|
df_profiles = pd.read_csv(os.path.join(data_folder, "profiles.csv"), index_col=[0, 1, 2])
|
|
|
|
df_sites = pd.read_csv(os.path.join(data_folder, 'sites.csv'), index_col=[0])
|
|
|
|
df_sites = pd.read_csv(os.path.join(data_folder, "sites.csv"), index_col=[0])
|
|
|
|
df_profile_features = pd.read_csv(os.path.join(data_folder, 'profile_features.csv'), index_col=[0])
|
|
|
|
df_profile_features = pd.read_csv(os.path.join(data_folder, "profile_features.csv"), index_col=[0])
|
|
|
|
|
|
|
|
|
|
|
|
logger.info('Forecasting TWL')
|
|
|
|
logger.info("Forecasting TWL")
|
|
|
|
|
|
|
|
|
|
|
|
df_twl_foreshore_slope_sto06 = forecast_twl(df_tides, df_profiles, df_waves, df_profile_features,
|
|
|
|
df_twl_foreshore_slope_sto06 = forecast_twl(
|
|
|
|
runup_function=sto06, slope='foreshore')
|
|
|
|
df_tides, df_profiles, df_waves, df_profile_features, runup_function=sto06, slope="foreshore"
|
|
|
|
df_twl_foreshore_slope_sto06.to_csv(os.path.join(data_folder, 'twl_foreshore_slope_sto06.csv'))
|
|
|
|
)
|
|
|
|
|
|
|
|
df_twl_foreshore_slope_sto06.to_csv(os.path.join(data_folder, "twl_foreshore_slope_sto06.csv"))
|
|
|
|
|
|
|
|
|
|
|
|
df_twl_mean_slope_sto06 = forecast_twl(df_tides, df_profiles, df_waves, df_profile_features,
|
|
|
|
df_twl_mean_slope_sto06 = forecast_twl(
|
|
|
|
runup_function=sto06, slope='mean')
|
|
|
|
df_tides, df_profiles, df_waves, df_profile_features, runup_function=sto06, slope="mean"
|
|
|
|
df_twl_mean_slope_sto06.to_csv(os.path.join(data_folder, 'twl_mean_slope_sto06.csv'))
|
|
|
|
)
|
|
|
|
|
|
|
|
df_twl_mean_slope_sto06.to_csv(os.path.join(data_folder, "twl_mean_slope_sto06.csv"))
|
|
|
|
|
|
|
|
|
|
|
|
logger.info('Done')
|
|
|
|
logger.info("Done")
|
|
|
|