gaia / compute_yield.py
Hugo Massonnat
change yield plot function for plots with no shading
d93b3a4
raw
history blame
7.39 kB
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)