Tutorial 2 - Fish Habitat Assessment using the MesoHABSIM Model

This tutorial demonstrates how to use the SARAwater package to assess fish habitat using the MesoHABSIM model.

Import libraries

[1]:
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sarawater as sara

plt.style.use("stylesheet.mplstyle")

I/O paths and directories creation

[2]:
input_csv_filepath = os.path.join("data", "daily_discharge_30y.csv")

Read the discharge data and create a reach object

Read the CSV data

[ ]:
reach_df = pd.read_csv(input_csv_filepath)

# Convert the first column to datetime
reach_df["Date"] = pd.to_datetime(reach_df["Date"])

# Convert the datetime column to a list of datetime objects
datetime_list = [t.to_pydatetime() for t in reach_df["Date"].tolist()]

# Put the discharge data into a numpy array
discharge_data = np.array(reach_df["Q"].to_list())

Initialize a reach object

[4]:
Qabs_max = 0.2
my_reach = sara.Reach("My Reach", datetime_list, discharge_data, Qabs_max)

Add scenarios to the reach object

Minimum release scenario (read from CSV)

[5]:
# Read the minimum release values from CSV relative to a Minimum Flow Requirement (MFR) policy
minrel_df = pd.read_csv(
    os.path.join("data", "minimum_flow_requirements.csv"), header=None
)

# Get the minimum release values (second column), convert l/s to m3/s
Qreq_months = np.array(minrel_df[1].tolist()) / 1000.0

# Create a constant scenario with these values
MFR_scenario = sara.ConstScenario(
    name="MFR",
    description="Minimum Flow Requirement scenario from CSV file",
    reach=my_reach,
    Qreq_months=Qreq_months,
)

# Add the scenario to the reach
my_reach.add_scenario(MFR_scenario)

# Print the min and max MFR values
min_mfr = MFR_scenario.Qreq_months.min()
max_mfr = MFR_scenario.Qreq_months.max()
print(f"MFR values range from {min_mfr:.3f} to {max_mfr:.3f} [m^3/s]")
MFR values range from 0.090 to 0.106 [m^3/s]

Ecological scenario (using the built-in method)

[6]:
my_reach.add_ecological_flow_scenario(
    "EF", "Ecological Flow Scenario with default parameters"
)
[6]:
Scenario(name=EF, description=Ecological Flow Scenario with default parameters, reach=My Reach)

Let’s check we added the scenarios correctly

[7]:
my_reach.print_scenarios()
scenarios[0]: MFR | Minimum Flow Requirement scenario from CSV file
scenarios[1]: EF | Ecological Flow Scenario with default parameters

Compute the released flow discharge and abstracted flow for each scenario

[8]:
for scenario in my_reach.scenarios:
    scenario.compute_Qrel()
    scenario.compute_natural_abstracted_volumes()

Habitat analysis

Read Habitat-Discharge curves from input data

[ ]:
HQ_curve_df = pd.read_csv(
    os.path.join("data", "HQ_curves.txt"), sep="\t", header="infer"
)
my_reach.add_HQ_curve(HQ_curve_df)
[ ]:
my_reach.get_list_available_HQ_curves()

Compute IH for each species and scenario

[ ]:
for scenario in my_reach.scenarios:
    scenario.compute_IH_for_species()
    for species in scenario.IH.keys():
        print(
            f"Scenario {scenario.name}, Species {species}, IH: {scenario.IH[species]['IH']}"
        )

Draw Plots

Initialize a ReachPlotter object

[12]:
plotter = sara.ReachPlotter(my_reach)

Full HQ curves

[13]:
plotter.plot_hq_curves()
[13]:
<Axes: title={'center': 'Habitat-Discharge (HQ) curves'}, xlabel='Q $[\\mathrm{m}^3/\\mathrm{s}]$', ylabel='Available area $[\\mathrm{m}^2]$'>
../../_images/tutorials_notebooks_tutorial_2_habitat_29_1.png

HQ curves setting xlim, and showing the DMV (or another constant scenario) range

[14]:
plotter.plot_hq_curves(xlim=0.4, rule_min=min_mfr, rule_max=max_mfr, rule_name="MFR")
[14]:
<Axes: title={'center': 'Habitat-Discharge (HQ) curves'}, xlabel='Q $[\\mathrm{m}^3/\\mathrm{s}]$', ylabel='Available area $[\\mathrm{m}^2]$'>
../../_images/tutorials_notebooks_tutorial_2_habitat_31_1.png

Habitat timeseries

[15]:
my_reach.get_list_available_HQ_curves()
[15]:
['BROW_A_R', 'MARB_A_R', 'TROU_J_R']
[16]:
plotter.plot_habitat_timeseries("BROW_A_R", start_year=2004, end_year=2004, save=True)
../../_images/tutorials_notebooks_tutorial_2_habitat_34_0.png

UCUT

[17]:
plotter.plot_ucut_curves("BROW_A_R")
../../_images/tutorials_notebooks_tutorial_2_habitat_36_0.png

IH_vs_volume

[18]:
plotter.plot_ih_vs_volume(save=True)
[18]:
<Axes: title={'center': 'My Reach - IH vs Abstracted Volume'}, xlabel='Habitat Index $(IH)$ [-]', ylabel='Normalized abstracted volume $V_{der}/V_{nat}$ [-]'>
../../_images/tutorials_notebooks_tutorial_2_habitat_38_1.png