gaia / compute_yield.py
Hugo Massonnat
change yield plot function for plots with no shading
d93b3a4
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from forecast import get_forecast_data
from retrieve_coefs_max_yield import get_coefs_Kc_Ky_and_max_yield
from utils.soil_utils import get_soil_properties
def calculate_ETx(Kc, ETo):
"""
Calculate the maximum evapotranspiration (ETx) using the crop coefficient (Kc) and reference evapotranspiration (ETo).
Parameters:
Kc (float): Crop coefficient
ETo (float): Reference evapotranspiration (mm)
Returns:
float: Maximum evapotranspiration (ETx) in mm
"""
ETx = Kc * ETo
return ETx
def calculate_ETa(ETx, soil_moisture, field_capacity, wilting_point, water_deficit, ETo):
"""
Calculate the actual evapotranspiration (ETa) using the maximum evapotranspiration (ETx), soil moisture, field capacity, and wilting point.
Parameters:
ETx (float): Maximum evapotranspiration (mm)
soil_moisture (Series): Current soil moisture content (%)
field_capacity (float): Field capacity of the soil (%)
wilting_point (float): Wilting point of the soil (%)
Returns:
float: Actual evapotranspiration (ETa) in mm
"""
Ks = 1 - (water_deficit / ETo) # coef de stress hydrique = precipitation / et0
Ks = Ks.clip(lower=0, upper=1)
ETa = ETx * Ks
ETa.loc[soil_moisture > field_capacity] = ETx.loc[soil_moisture > field_capacity]
ETa.loc[soil_moisture < wilting_point] = 0
return ETa
def calculate_yield_projection(Yx, ETx, ETa, Ky):
"""
Calculate the agricultural yield projection using the FAO water production function.
Parameters:
Yx (float): Maximum yield (quintal/ha)
ETx (float): Maximum evapotranspiration (mm)
ETa (float): Actual evapotranspiration (mm)
Ky (float): Yield response factor
Returns:
float: Projected yield (quintal/ha)
"""
Ya = Yx * (1 - Ky * (1 - ETa / ETx))
Ya.loc[ETx == 0] = 0
return round(Ya, 2)
def add_cultural_coefs(monthly_forecast: pd.DataFrame, cultural_coefs: pd.DataFrame) -> pd.DataFrame:
monthly_forecast["Kc"] = 0
monthly_forecast["Ky"] = 0
for month in range(1, 13):
Kc = cultural_coefs["Kc"][cultural_coefs.Mois == month].iloc[0]
Ky = cultural_coefs["Ky"][cultural_coefs.Mois == month].iloc[0]
monthly_forecast.loc[(monthly_forecast.month==month).to_numpy(), "Kc"] = Kc
monthly_forecast.loc[(monthly_forecast.month==month).to_numpy(), "Ky"] = Ky
return monthly_forecast
def compute_yield_forecast(
latitude: float,
longitude: float,
culture: str = "Colza d'hiver",
region: str = "Bourgogne-Franche-Comté",
scenario: str = "pessimist",
shading_coef: float = 0.,
):
monthly_forecast = get_forecast_data(latitude, longitude, scenario=scenario, shading_coef=shading_coef)
cultural_coefs, max_yield = get_coefs_Kc_Ky_and_max_yield(culture, region)
monthly_forecast = add_cultural_coefs(monthly_forecast, cultural_coefs)
Kc = monthly_forecast["Kc"]
Ky = monthly_forecast["Ky"]
soil_properties = get_soil_properties(latitude, longitude)
ETo = monthly_forecast["Evaporation (mm/day)"]
ETx = calculate_ETx(Kc, ETo)
ETa = calculate_ETa(
ETx,
monthly_forecast["Moisture in Upper Portion of Soil Column (kg m-2)"],
soil_properties["field_capacity"],
soil_properties["wilting_point"],
water_deficit=monthly_forecast["Water Deficit (mm/day)"],
ETo=ETo,
)
projected_yield = calculate_yield_projection(
Yx=max_yield,
ETx=ETx,
ETa=ETa,
Ky=Ky)
monthly_forecast["Estimated yield (quintal/ha)"] = projected_yield
return monthly_forecast
def get_annual_yield(monthly_forecast: pd.DataFrame) -> pd.Series:
yield_forecast = pd.Series(
index=monthly_forecast["time"],
data=monthly_forecast["Estimated yield (quintal/ha)"].to_numpy(),
)
yield_forecast = yield_forecast.resample("1YE").mean()
return yield_forecast
def plot_yield(
latitude: float,
longitude: float,
culture: str = "Colza d'hiver",
region: str = "Bourgogne-Franche-Comté",
scenario: str = "pessimist",
shading_coef: float = 0.2,
) -> plt.Figure:
monthly_forecast = compute_yield_forecast(
latitude=latitude,
longitude=longitude,
culture=culture,
scenario=scenario,
shading_coef=0.,
)
yield_forecast = get_annual_yield(monthly_forecast)
n_years = 10
years = 2025 + np.arange(len(yield_forecast))
aggregated_years = years[years % n_years == 0]
aggregated_forecasts = yield_forecast.rolling(n_years).sum()[years % n_years == 0]
width = 3 # the width of the bars
fig, ax = plt.subplots(layout='constrained')
_ = ax.bar(aggregated_years, aggregated_forecasts, width, label="No shading")
if shading_coef > 0:
monthly_forecast_with_shading = compute_yield_forecast(
latitude=latitude,
longitude=longitude,
culture=culture,
scenario=scenario,
shading_coef=shading_coef,
)
yield_forecast_with_shading = get_annual_yield(monthly_forecast_with_shading)
aggregated_forecasts_with_shading = yield_forecast_with_shading.rolling(n_years).sum()[years % n_years == 0]
_ = ax.bar(aggregated_years + width, aggregated_forecasts_with_shading, width, label="20% shading")
ax.legend()
ax.set_xlabel("Année")
ax.set_ylabel(f"Production agricole de {culture} estimée (quintal / ha)")
ax.set_ylim(150)
return fig
if __name__ == '__main__':
latitude = 47
longitude = 5
cultures = ["Colza d'hiver", "Blé tendre d'hiver", "Orge d'hiver"]
dfs = []
for culture in cultures:
scenario = "pessimist"
shading_coef = 0.2
monthly_forecast = compute_yield_forecast(
latitude=47,
longitude=5,
culture=culture,
scenario=scenario,
shading_coef=0.,
)
monthly_forecast_with_shading = compute_yield_forecast(
latitude=47,
longitude=5,
culture=culture,
scenario=scenario,
shading_coef=shading_coef,
)
fig = plot_yield(latitude, longitude, culture, scenario="pessimist", shading_coef=shading_coef)
plt.show()
# yield_forecast = get_annual_yield(monthly_forecast)
# yield_forecast_df = yield_forecast.reset_index()
# yield_forecast_df.columns = ["time", "yield_simple_forecast"]
# yield_forecast_df["year"] = yield_forecast_df["time"].dt.year
# yield_forecast_with_shading = get_annual_yield(monthly_forecast_with_shading)
# yield_forecast_with_shading_df = yield_forecast_with_shading.reset_index()
# yield_forecast_with_shading_df.columns = ["time", "yield_with_shading_forecast"]
# yield_forecast_with_shading_df["year"] = yield_forecast_with_shading_df["time"].dt.year
# final_df = pd.merge(yield_forecast_df[["year", "yield_simple_forecast"]], yield_forecast_with_shading_df[["year", "yield_with_shading_forecast"]], on="year")
# final_df["culture"] = culture
# dfs.append(final_df)
# result = pd.concat(dfs, axis=0)
# result.to_csv("data/data_yield/rendement_forecast.csv", index=False)