|
|
|
@ -41,13 +41,16 @@ def forecast_twl(
|
|
|
|
|
# Process each site_id with a different process and combine results at the end
|
|
|
|
|
with Pool(processes=n_processes) as pool:
|
|
|
|
|
results = pool.starmap(
|
|
|
|
|
foreshore_slope_for_site_id, [(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)
|
|
|
|
|
|
|
|
|
|
elif slope == "mean":
|
|
|
|
|
df_temp = df_twl.join(
|
|
|
|
|
df_profile_features.query("profile_type=='{}'".format(profile_type)).reset_index(level="profile_type"),
|
|
|
|
|
df_profile_features.query(
|
|
|
|
|
"profile_type=='{}'".format(profile_type)
|
|
|
|
|
).reset_index(level="profile_type"),
|
|
|
|
|
how="inner",
|
|
|
|
|
)
|
|
|
|
|
df_temp["mhw"] = 0.5
|
|
|
|
@ -59,19 +62,26 @@ def forecast_twl(
|
|
|
|
|
df_temp.dune_toe_z.isnull(), "dune_crest_z"
|
|
|
|
|
]
|
|
|
|
|
df_temp["top_x"] = df_temp["dune_toe_x"]
|
|
|
|
|
df_temp.loc[df_temp.dune_toe_x.isnull(), "top_x"] = df_temp.loc[df_temp.dune_toe_x.isnull(), "dune_crest_x"]
|
|
|
|
|
df_temp.loc[df_temp.dune_toe_x.isnull(), "top_x"] = df_temp.loc[
|
|
|
|
|
df_temp.dune_toe_x.isnull(), "dune_crest_x"
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
with Pool(processes=n_processes) as pool:
|
|
|
|
|
results = pool.starmap(
|
|
|
|
|
mean_slope_for_site_id,
|
|
|
|
|
[(site_id, df_temp, df_profiles, "top_elevation", "top_x", "mhw") for site_id in site_ids],
|
|
|
|
|
[
|
|
|
|
|
(site_id, df_temp, df_profiles, "top_elevation", "top_x", "mhw")
|
|
|
|
|
for site_id in site_ids
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
df_twl["beta"] = pd.concat(results)
|
|
|
|
|
|
|
|
|
|
# Estimate runup
|
|
|
|
|
R2, setup, S_total, S_inc, S_ig = runup_function(
|
|
|
|
|
Hs0=df_twl["Hs0"].tolist(), Tp=df_twl["Tp"].tolist(), beta=df_twl["beta"].tolist()
|
|
|
|
|
Hs0=df_twl["Hs0"].tolist(),
|
|
|
|
|
Tp=df_twl["Tp"].tolist(),
|
|
|
|
|
beta=df_twl["beta"].tolist(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
df_twl["R2"] = R2
|
|
|
|
@ -80,7 +90,9 @@ def forecast_twl(
|
|
|
|
|
|
|
|
|
|
# Estimate TWL
|
|
|
|
|
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
|
|
|
|
|
# df_twl.drop(columns=["E", "Exs", "P", "Pxs", "dir"], inplace=True, errors="ignore")
|
|
|
|
@ -89,7 +101,13 @@ def forecast_twl(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def mean_slope_for_site_id(
|
|
|
|
|
site_id, df_twl, df_profiles, top_elevation_col, top_x_col, btm_elevation_col, profile_type="prestorm"
|
|
|
|
|
site_id,
|
|
|
|
|
df_twl,
|
|
|
|
|
df_profiles,
|
|
|
|
|
top_elevation_col,
|
|
|
|
|
top_x_col,
|
|
|
|
|
btm_elevation_col,
|
|
|
|
|
profile_type="prestorm",
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
Calculates the foreshore slope values a given site_id. Returns a series (with same indicies as df_twl) of
|
|
|
|
@ -135,7 +153,9 @@ def foreshore_slope_for_site_id(site_id, df_twl, df_profiles):
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# 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_z = profile.z.tolist()
|
|
|
|
|
|
|
|
|
@ -175,8 +195,12 @@ def foreshore_slope_from_profile(profile_x, profile_z, tide, runup_function, **k
|
|
|
|
|
# Initalize estimates
|
|
|
|
|
max_number_iterations = 30
|
|
|
|
|
iteration_count = 0
|
|
|
|
|
averaged_accuracy = 0.03 # if slopes within this amount, average after max number of iterations
|
|
|
|
|
acceptable_accuracy = 0.01 # if slopes within this amount, accept after max number of iterations
|
|
|
|
|
averaged_accuracy = (
|
|
|
|
|
0.03
|
|
|
|
|
) # if slopes within this amount, average after max number of iterations
|
|
|
|
|
acceptable_accuracy = (
|
|
|
|
|
0.01
|
|
|
|
|
) # if slopes within this amount, accept after max number of iterations
|
|
|
|
|
preferred_accuracy = 0.001 # if slopes within this amount, accept
|
|
|
|
|
beta = 0.05
|
|
|
|
|
|
|
|
|
@ -212,7 +236,15 @@ def foreshore_slope_from_profile(profile_x, profile_z, tide, runup_function, **k
|
|
|
|
|
iteration_count += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, method="end_points", top_x=None, btm_x=None):
|
|
|
|
|
def slope_from_profile(
|
|
|
|
|
profile_x,
|
|
|
|
|
profile_z,
|
|
|
|
|
top_elevation,
|
|
|
|
|
btm_elevation,
|
|
|
|
|
method="end_points",
|
|
|
|
|
top_x=None,
|
|
|
|
|
btm_x=None,
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
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
|
|
|
|
@ -260,7 +292,9 @@ def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, metho
|
|
|
|
|
end_points[end_type]["x"] = intersection_x[-1]
|
|
|
|
|
else:
|
|
|
|
|
# For bottom elevation, take most landward intersection that is seaward of top elevation
|
|
|
|
|
end_point_btm = [x for x in intersection_x if x > end_points["top"]["x"]]
|
|
|
|
|
end_point_btm = [
|
|
|
|
|
x for x in intersection_x if x > end_points["top"]["x"]
|
|
|
|
|
]
|
|
|
|
|
if len(end_point_btm) == 0:
|
|
|
|
|
# If there doesn't seem to be an intersection seaward of the top elevation, return none.
|
|
|
|
|
return None
|
|
|
|
@ -275,7 +309,10 @@ def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, metho
|
|
|
|
|
return -(z_top - z_btm) / (x_top - x_btm)
|
|
|
|
|
|
|
|
|
|
elif method == "least_squares":
|
|
|
|
|
profile_mask = [True if end_points["top"]["x"] < pts < end_points["btm"]["x"] else False for pts in profile_x]
|
|
|
|
|
profile_mask = [
|
|
|
|
|
True if end_points["top"]["x"] < pts < end_points["btm"]["x"] else False
|
|
|
|
|
for pts in profile_x
|
|
|
|
|
]
|
|
|
|
|
slope_x = np.array(profile_x)[profile_mask].tolist()
|
|
|
|
|
slope_z = np.array(profile_z)[profile_mask].tolist()
|
|
|
|
|
slope, _, _, _, _ = stats.linregress(slope_x, slope_z)
|
|
|
|
@ -287,12 +324,28 @@ def slope_from_profile(profile_x, profile_z, top_elevation, btm_elevation, metho
|
|
|
|
|
@click.option("--tides-csv", required=True, help="")
|
|
|
|
|
@click.option("--profiles-csv", required=True, help="")
|
|
|
|
|
@click.option("--profile-features-csv", required=True, help="")
|
|
|
|
|
@click.option("--runup-function", required=True, help="", type=click.Choice(["sto06"]))
|
|
|
|
|
@click.option("--slope", required=True, help="", type=click.Choice(["foreshore", "mean"]))
|
|
|
|
|
@click.option("--profile-type", required=True, help="", type=click.Choice(["prestorm", "poststorm"]))
|
|
|
|
|
@click.option(
|
|
|
|
|
"--runup-function", required=True, help="", type=click.Choice(["sto06", "hol86"])
|
|
|
|
|
)
|
|
|
|
|
@click.option(
|
|
|
|
|
"--slope", required=True, help="", type=click.Choice(["foreshore", "mean"])
|
|
|
|
|
)
|
|
|
|
|
@click.option(
|
|
|
|
|
"--profile-type",
|
|
|
|
|
required=True,
|
|
|
|
|
help="",
|
|
|
|
|
type=click.Choice(["prestorm", "poststorm"]),
|
|
|
|
|
)
|
|
|
|
|
@click.option("--output-file", required=True, help="")
|
|
|
|
|
def create_twl_forecast(
|
|
|
|
|
waves_csv, tides_csv, profiles_csv, profile_features_csv, runup_function, slope, profile_type, output_file
|
|
|
|
|
waves_csv,
|
|
|
|
|
tides_csv,
|
|
|
|
|
profiles_csv,
|
|
|
|
|
profile_features_csv,
|
|
|
|
|
runup_function,
|
|
|
|
|
slope,
|
|
|
|
|
profile_type,
|
|
|
|
|
output_file,
|
|
|
|
|
):
|
|
|
|
|
logger.info("Creating forecast of total water levels")
|
|
|
|
|
logger.info("Importing data")
|
|
|
|
|