From c2cc08625dcddbed514d69d17865a6643bc876ec Mon Sep 17 00:00:00 2001 From: Ricardo Garcia Silva Date: Thu, 29 Aug 2024 18:26:59 +0100 Subject: [PATCH 1/2] Started implementation of menu-generating operation --- arpav_ppcv/operations.py | 124 ++++++++++- tests/notebooks/generic.ipynb | 374 +++++++++++++++++++++++----------- 2 files changed, 377 insertions(+), 121 deletions(-) diff --git a/arpav_ppcv/operations.py b/arpav_ppcv/operations.py index da022dea..431b1be5 100644 --- a/arpav_ppcv/operations.py +++ b/arpav_ppcv/operations.py @@ -3,7 +3,10 @@ import io import logging import warnings -from typing import Optional +from typing import ( + Optional, + TypedDict, +) import anyio import cftime @@ -893,3 +896,122 @@ def _get_spatial_buffer( point_geom_projected, distance=distance_meters ) return transform(inverse_coordinate_transformer, buffer_geom_projected) + + +class ForecastVariableMenuTreeCombination(TypedDict): + configuration_parameter: coverages.ConfigurationParameter + values: list[coverages.ConfigurationParameterPossibleValue] + + +class ForecastVariableMenuTree(TypedDict): + climatological_variable: coverages.ConfigurationParameterPossibleValue + aggregation_period: coverages.ConfigurationParameterPossibleValue + measure: coverages.ConfigurationParameterPossibleValue + combinations: dict[str, ForecastVariableMenuTreeCombination] + + +def get_forecast_variable_parameters( + session: sqlmodel.Session, +) -> dict[str, ForecastVariableMenuTree]: + # - retrieve all the cov confs that have the variable + # - for each cov conf, aggregate by aggregation_period and measure + result = {} + all_cov_confs = database.collect_all_coverage_configurations(session) + for cov_conf in all_cov_confs: + variable_pvs = [ + pv + for pv in cov_conf.possible_values + if pv.configuration_parameter_value.configuration_parameter.name + == "climatological_variable" + ] + if (num_pvs := len(variable_pvs)) >= 1: + variable_pv = variable_pvs[0] + if num_pvs > 1: + logger.info( + f"coverage configuration {cov_conf.name!r} defines " + f"{len(variable_pvs)} `climatological_variable`s, keeping only the " + f"first one..." + ) + else: + logger.info( + f"coverage configuration {cov_conf.name!r} does not have a " + f"`climatological_variable`, skipping..." + ) + continue + + aggreg_period_pvs = [ + pv + for pv in cov_conf.possible_values + if pv.configuration_parameter_value.configuration_parameter.name + == "aggregation_period" + ] + if (num_aggreg_periods := len(aggreg_period_pvs)) >= 1: + aggreg_period_pv = aggreg_period_pvs[0] + if num_aggreg_periods > 1: + logger.info( + f"coverage configuration {cov_conf.name!r} defines " + f"{len(variable_pvs)} `aggregation_period`s, keeping only the " + f"first one..." + ) + else: + logger.info( + f"coverage configuration {cov_conf.name!r} does not have a " + f"`aggregation_period`, skipping..." + ) + continue + + measure_pvs = [ + pv + for pv in cov_conf.possible_values + if pv.configuration_parameter_value.configuration_parameter.name + == "measure" + ] + if (num_measures := len(measure_pvs)) >= 1: + measure_pv = measure_pvs[0] + if num_measures > 1: + logger.info( + f"coverage configuration {cov_conf.name!r} defines " + f"{len(variable_pvs)} `measures`s, keeping only the " + f"first one..." + ) + else: + logger.info( + f"coverage configuration {cov_conf.name!r} does not have a " + f"`measure`, skipping..." + ) + continue + + result_key = "-".join( + ( + variable_pv.configuration_parameter_value.name, + aggreg_period_pv.configuration_parameter_value.name, + measure_pv.configuration_parameter_value.name, + ) + ) + aggregated_variable = result.setdefault(result_key, {}) + aggregated_variable[ + "climatological_variable" + ] = variable_pv.configuration_parameter_value + aggregated_variable[ + "aggregation_period" + ] = aggreg_period_pv.configuration_parameter_value + aggregated_variable["measure"] = measure_pv.configuration_parameter_value + combinations = aggregated_variable.setdefault("combinations", {}) + params_to_ignore = ( + "climatological_variable", + "aggregation_period", + "measure", + "uncertainty_type", + ) + for pv in cov_conf.possible_values: + param_name = pv.configuration_parameter_value.configuration_parameter.name + if param_name not in params_to_ignore: + param_entry = combinations.setdefault(param_name, {}) + param_entry[ + "configuration_parameter" + ] = pv.configuration_parameter_value.configuration_parameter + values = param_entry.setdefault("values", []) + existing_value_names = [cpv.name for cpv in values] + if pv.configuration_parameter_value.name not in existing_value_names: + values.append(pv.configuration_parameter_value) + return result diff --git a/tests/notebooks/generic.ipynb b/tests/notebooks/generic.ipynb index 5352ac95..6fe02b08 100644 --- a/tests/notebooks/generic.ipynb +++ b/tests/notebooks/generic.ipynb @@ -51,137 +51,271 @@ }, { "cell_type": "code", - "execution_count": 6, - "id": "c65166b7-4173-444c-be69-688ff5f6b874", + "execution_count": 2, + "id": "839244fc-728f-47b3-9a72-a1011b87b38a", + "metadata": {}, + "outputs": [], + "source": [ + "all_cov_confs = db.collect_all_coverage_configurations(session)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ea47a457-5196-4a4f-a13e-677620338211", "metadata": {}, "outputs": [], "source": [ - "station = db.get_station_by_code(session, '91')" + "cc = all_cov_confs[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "a220dfd1-5f66-49b2-a9fe-5b51708f08e6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'year_period'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cc.possible_values[0].configuration_parameter_value.configuration_parameter.name" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "f296518d-c9b0-4c32-8e9b-216a420ee6ef", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ConfigurationParameterPossibleValue(configuration_parameter_value_id=UUID('dae44b14-c413-44db-8970-f2236b70028a'), coverage_configuration_id=UUID('268a76ab-4675-4234-a212-15108fa693d7'))" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[pv for pv in cc.possible_values if pv.configuration_parameter_value.configuration_parameter.name == \"climatological_variable\"][0]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "4813b978-ab43-4897-805b-394c45be70e2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'MAM'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cc.possible_values[0].configuration_parameter_value.name" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "97e789b2-721b-4e10-baa4-8b4bb39d3ade", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:arpav_ppcv.operations:coverage configuration 'tas_barometro_climatico' does not have a `aggregation_period`, skipping...\n", + "INFO:arpav_ppcv.operations:coverage configuration 'tas_barometro_climatico_lower_uncertainty' does not have a `aggregation_period`, skipping...\n", + "INFO:arpav_ppcv.operations:coverage configuration 'tas_barometro_climatico_upper_uncertainty' does not have a `aggregation_period`, skipping...\n" + ] + } + ], + "source": [ + "result = operations.get_forecast_variable_parameters(session)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "25c2ade2-e3e7-418a-b19a-97023ea76d24", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['tas-30yr-anomaly', 'tas-annual-absolute', 'tas-annual-anomaly']" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[k for k in result.keys() if \"tas-\" in k]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "8dc2ad3d-6729-46e8-8fea-b2b2257dfe81", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['climatological_variable', 'aggregation_period', 'measure', 'combinations'])" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result[\"tas-30yr-anomaly\"].keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "dd151151-4344-42e3-8a19-d2a6ad6d252a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ConfigurationParameterValue(id=UUID('e6ff2bf7-67c4-48f9-ad3a-e0737cc2c07a'), display_name_italian='TAS', description_italian='Temperatura media', name='tas', display_name_english='TAS', description_english='Mean temperature', configuration_parameter_id=UUID('12dfb711-9c18-46ac-8fc5-0b902eb48964'))" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result[\"tas-30yr-anomaly\"][\"climatological_variable\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "01884c1d-df69-429c-824b-bdde3f115386", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ConfigurationParameterValue(id=UUID('b137bb59-a00b-4ed0-a5ea-3ecb4d6c9f7f'), display_name_italian='30 anni', description_italian=\"I set di dati contengono un'aggregazione di 30 anni\", name='30yr', display_name_english='30 Years', description_english='Datasets contain aggregation of 30 years', configuration_parameter_id=UUID('52732ef9-db4c-48af-984f-39b35f3f4fa2'))" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result[\"tas-30yr-anomaly\"][\"aggregation_period\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "97ffbb61-826e-4d5b-be1d-e1fa77769fd8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ConfigurationParameterValue(id=UUID('dab01644-d1cd-4b31-91ae-34a17b5292f5'), display_name_italian='Anomalia climatologica', description_italian='Rappresenta i valori di anomalia climatologica per la variabile', name='anomaly', display_name_english='Climatological anomaly', description_english='Represents climatological anomaly values for the variable', configuration_parameter_id=UUID('ab4becc0-57db-4716-b8d4-b3ca5eba0ce9'))" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result[\"tas-30yr-anomaly\"][\"measure\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "391a7eb9-9ae5-4085-b4f5-2ac3364bbd7f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['year_period', 'climatological_model', 'scenario', 'time_window'])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result[\"tas-30yr-anomaly\"][\"combinations\"].keys()" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "9672f748-b3d4-48a1-b2f7-f0c60ec4f9d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ConfigurationParameterValue(id=UUID('1021b1a8-9e9f-4c90-b483-9211bc17c2e0'), display_name_italian='Primavera', description_italian='Stagione climatologica primaverile (marzo, aprile, maggio)', name='MAM', display_name_english='Spring', description_english='Climatological spring season (March, April, May)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('731991b0-d6fd-48ad-976a-3519ee5e8e52'), display_name_italian='Estate', description_italian='Stagione climatologica estiva (giugno, luglio, agosto)', name='JJA', display_name_english='Summer', description_english='Climatological summer season (June, July, August)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('94b9b78b-e344-4288-a4e8-aa54f83ef63e'), display_name_italian='Autunno', description_italian='Stagione climatologica autunnale (settembre, ottobre, novembre)', name='SON', display_name_english='Autumn', description_english='Climatological autumn season (September, October, November)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('ff4e7c7b-7141-4d37-8979-3c5714ac4b4d'), display_name_italian='Inverno', description_italian='Stagione climatologica invernale (dicembre, gennaio, febbraio)', name='DJF', display_name_english='Winter', description_english='Climatological winter season (December, January, February)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767'))]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result[\"tas-30yr-anomaly\"][\"combinations\"][\"year_period\"][\"values\"]" ] }, { "cell_type": "code", "execution_count": 12, - "id": "1b50e512-cff5-4f30-8576-9e2ea92a2948", + "id": "e592a4de-9a39-46f2-81f0-205c6bdd9cfb", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[MonthlyMeasurement(date=datetime.date(1987, 1, 1), id=UUID('0f78a845-0db1-45ef-bac8-03f8d68ff034'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-8.23, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1988, 1, 1), id=UUID('cbe5ba03-9996-44b8-b707-1b29b1fb309f'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.34, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1989, 1, 1), id=UUID('103497ee-ec72-4b1b-8992-2e1aea3270a3'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.42, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1990, 1, 1), id=UUID('761f4b69-18f7-4364-9660-88a5813d15d7'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.319, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1991, 1, 1), id=UUID('bff40fed-5a6c-493b-ba53-eda0e63fd769'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.142, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1992, 1, 1), id=UUID('8dbbc233-69c6-467c-971b-6dfbaab56977'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.258, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1993, 1, 1), id=UUID('7ef47fa6-319b-4d06-a84f-b2f56d253350'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.173, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1994, 1, 1), id=UUID('7200af2a-b69a-4d3c-ba90-bc7f90f485ab'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.869, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1995, 1, 1), id=UUID('d28b8b45-fde5-470f-ab69-4b3c5be1ffaf'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.462, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1996, 1, 1), id=UUID('c00db9a3-5c1d-40ef-b8df-f13ad686cb1b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.689, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1997, 1, 1), id=UUID('b56ca768-245d-4449-b91c-8fc2a6fc1534'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.899, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1998, 1, 1), id=UUID('9cdc48c9-415f-4dcb-b431-640f1016a9ec'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.719, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1999, 1, 1), id=UUID('5a154810-13b3-4085-854c-3d799c419b4d'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.364, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2000, 1, 1), id=UUID('f5697a14-a556-4852-9036-998bef18b9b8'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.684, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2001, 1, 1), id=UUID('38b80371-1276-43f9-80be-402e7ed5a500'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.417, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2002, 1, 1), id=UUID('7ef9ec16-6d33-4f9d-bed9-9d01d1aee217'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.836, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2003, 1, 1), id=UUID('d69f3e20-df1f-403f-a156-7e7c7d9abbfd'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.316, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2004, 1, 1), id=UUID('0952716a-32ac-4330-83f0-7843d5f1d035'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.396, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2005, 1, 1), id=UUID('25be0365-df31-435c-850e-52c86a7fe3d9'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.101, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2006, 1, 1), id=UUID('1011c8c2-4321-418f-8575-5781ee6ce622'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.783, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2007, 1, 1), id=UUID('ba8b7181-38e6-4a5b-9d67-8f68fc412d01'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.012, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2008, 1, 1), id=UUID('575070e0-c530-486e-93f4-a68ad1ddaeca'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.732, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2009, 1, 1), id=UUID('5e3d1444-82da-4c68-abe5-ba2a8235c3e1'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.439, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2010, 1, 1), id=UUID('5252e177-d5a9-4506-bb0d-0645a84356dc'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.29, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2011, 1, 1), id=UUID('b1dcff4d-821e-4244-8f82-f3323af49656'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.125, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2012, 1, 1), id=UUID('250231cd-e60a-4bef-abee-8c5d23e8d152'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.426, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2013, 1, 1), id=UUID('c9cbee38-bff2-4ebb-95cf-90c808a708d7'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.209, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2014, 1, 1), id=UUID('982e38cb-2731-4388-907a-c6fd5c12360a'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.847, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2015, 1, 1), id=UUID('7839d9bb-754a-480f-bdb9-70b17a63fe76'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.711, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2016, 1, 1), id=UUID('50f5de6f-bdda-47e4-8275-cb27b41dcc37'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.264, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2017, 1, 1), id=UUID('cd77a4d3-ac54-40cc-95ff-8c6f65e4396e'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.088, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2018, 1, 1), id=UUID('74cb0cd1-aa31-481f-80a8-f6cd15e5f139'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.445, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2019, 1, 1), id=UUID('429d51d7-4e15-4a52-841d-c401c09b2014'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.142, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2020, 1, 1), id=UUID('a6aeba0c-9bda-4cb0-b0f7-d8f8dfc96dfa'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.529, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2021, 1, 1), id=UUID('8904539a-3e35-4ca2-9898-f689a67f7731'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.025, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2022, 1, 1), id=UUID('c49f306c-d3e0-4098-bd86-80179c8067ce'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.885, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2023, 1, 1), id=UUID('9b86e4ef-407b-4235-9c45-930256ad1726'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.724, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2024, 1, 1), id=UUID('e99c0233-0c7f-4cd4-9182-e2f6a12b142f'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.711, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1987, 2, 1), id=UUID('b12da42a-f1bb-4c61-9f24-6ca83811c34a'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.191, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1988, 2, 1), id=UUID('91c90ec3-3d04-45e0-967f-58347decb673'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.257, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1989, 2, 1), id=UUID('aa56f60d-b35d-4c6b-b8ee-714957197998'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.728, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1990, 2, 1), id=UUID('54eceede-7336-42ce-8802-2d44c640e503'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.483, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1991, 2, 1), id=UUID('1ea84e16-d746-40fe-ab6c-e5bffe05193d'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.46, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1992, 2, 1), id=UUID('a1e3ab1e-27d9-4507-b1ea-2efa8a6c6241'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.505, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1993, 2, 1), id=UUID('30390ec6-acb8-44e4-af11-ce1fbd91c0fc'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-4.174, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1994, 2, 1), id=UUID('c650ee0b-2da2-468a-b758-ac1a70658c17'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.704, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1995, 2, 1), id=UUID('5e86d247-08a0-4ffb-b70f-c9186827d4eb'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.047, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1996, 2, 1), id=UUID('41af8b32-68fb-4170-8e1d-ca07a0222328'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.12, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1997, 2, 1), id=UUID('6c244bd9-facc-4a90-9df0-95f962be9983'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.522, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1998, 2, 1), id=UUID('e2e94424-9d91-4947-b60c-672553160b9b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-0.488, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1999, 2, 1), id=UUID('448df967-be0e-4943-8867-540253a8bef0'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.811, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2000, 2, 1), id=UUID('4d3cf120-0ca9-448e-8bc1-1897c7feb096'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.198, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2001, 2, 1), id=UUID('30104e41-32ee-40ce-9568-133cb849659d'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.647, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2002, 2, 1), id=UUID('7a01ba38-4f7d-4c60-aa69-d27cdab0b26f'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.02, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2003, 2, 1), id=UUID('b44ad8b8-7aaa-4d05-ae08-513e86c30d66'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.398, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2004, 2, 1), id=UUID('dc8e2010-6eee-4dbd-b1aa-c377c42a83ee'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.356, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2005, 2, 1), id=UUID('fa9c469c-448e-4afe-b3b3-e24e3df3e606'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-8.506, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2006, 2, 1), id=UUID('40b3f7ba-d835-4d4c-b32b-094c360ae7fa'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.09, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2007, 2, 1), id=UUID('032c0f4a-dd86-4e2a-94cd-bc0b53d9c0c6'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.817, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2008, 2, 1), id=UUID('1b575ebb-05a0-4b79-a7f4-5928bad72c78'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.206, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2009, 2, 1), id=UUID('8b629a67-2635-435e-bb46-d0a11149fac4'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.089, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2010, 2, 1), id=UUID('d9ee16e5-24dc-432e-a7ac-6cdcbfa8c356'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-5.43, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2011, 2, 1), id=UUID('10ab2fc0-d4ce-49f7-b900-13b8922fa563'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.327, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2012, 2, 1), id=UUID('681dc9de-9cbe-43dc-8c88-ab173a5edfba'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.829, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2013, 2, 1), id=UUID('1e4aff17-c85e-4683-a26f-3bef37fa8618'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.85, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2014, 2, 1), id=UUID('bdc566bc-a362-4ef0-a30c-b2d7f1ece2dc'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.385, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2015, 2, 1), id=UUID('86a17661-4516-427b-b780-2a01a02ee248'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.672, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2016, 2, 1), id=UUID('ff35b841-0aa6-4219-a04a-e7516f996d19'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.108, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2017, 2, 1), id=UUID('0e0b64af-548f-40e4-99bc-969c9bd171d7'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.934, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2018, 2, 1), id=UUID('d3ee9290-507f-4896-8638-af1bd4e275d9'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-7.353, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2019, 2, 1), id=UUID('bf3b915c-25fa-4033-94b2-b5bb3d23d879'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.03, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2020, 2, 1), id=UUID('527990c6-00f2-4410-a852-d24c687d97db'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.433, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2021, 2, 1), id=UUID('6138ad4b-00c2-4431-addd-510b6ff16f56'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.675, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2022, 2, 1), id=UUID('fdcf195a-f21d-425c-b423-7b530aa1a500'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.621, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2023, 2, 1), id=UUID('d4ee7b92-bbdb-4e8b-b2a6-a41b8385610b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.731, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2024, 2, 1), id=UUID('20ca569b-c3be-413e-86f5-e16a7ac00346'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.294, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1987, 3, 1), id=UUID('5dbd93e6-9b12-440c-a3c5-192023d52f64'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-6.552, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1988, 3, 1), id=UUID('12a35164-e140-4da9-a98d-f508f21ed5b7'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.824, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1989, 3, 1), id=UUID('d2e81189-b422-4dc8-be7b-a96289507627'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.527, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1990, 3, 1), id=UUID('1540a46d-080e-42f1-91c9-ba14d1ce151a'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.903, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1991, 3, 1), id=UUID('ccc1a89c-7f98-4c5c-b5b8-b37a68afd3a2'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.611, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1992, 3, 1), id=UUID('b1be00be-b5d8-4318-bb6b-672848af12b5'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.327, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1993, 3, 1), id=UUID('40401c73-a278-4fae-8e70-7be44a0c05b1'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.725, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1994, 3, 1), id=UUID('dcea512e-347f-4bcc-9605-b3234646f33d'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=2.175, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1995, 3, 1), id=UUID('271ae6f3-64cc-4237-90f3-5d0b9334e68a'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.626, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1996, 3, 1), id=UUID('a5f45d08-4f4b-4671-bd63-357d0b0ebe7b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.929, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1997, 3, 1), id=UUID('f63fce08-d43c-4ab4-9b86-db98caae46be'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=1.293, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1998, 3, 1), id=UUID('3a2c5306-5283-450b-a1d7-35dbbe74125b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.795, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(1999, 3, 1), id=UUID('ab65207d-7cd4-4ac8-ac36-c3ce35571cdf'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-0.698, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2000, 3, 1), id=UUID('87857a78-7b53-4d0a-9f65-7d55b7d28457'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-0.537, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2001, 3, 1), id=UUID('a3d59359-f202-4e2e-9841-7a0f5095c9da'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.439, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2002, 3, 1), id=UUID('9bbd7327-24c3-437d-922e-ca53ad3f5872'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.567, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2003, 3, 1), id=UUID('688a1152-08de-46d4-80a6-ece7852f380b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=1.007, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2004, 3, 1), id=UUID('c1942d73-72b8-4e74-859a-be05f195f45e'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.205, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2005, 3, 1), id=UUID('b2e0aee0-0df2-474c-a98d-da1ef82ecad5'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.307, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2006, 3, 1), id=UUID('a06f53dc-f1af-47f2-b965-f794982ee146'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-3.633, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2007, 3, 1), id=UUID('50657e6c-ffd1-4268-b56d-030326b29835'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-0.684, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2008, 3, 1), id=UUID('e342d985-b658-4f0b-b480-a22b103cd8a2'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.245, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2009, 3, 1), id=UUID('d24cd8c1-b6e5-4bc0-bbd3-5709a9cc62b1'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.051, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2010, 3, 1), id=UUID('bfd745be-13a7-43a1-89f2-e690e2a26543'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.303, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2011, 3, 1), id=UUID('756776d5-0a11-4eed-8d3c-9bf270ce315c'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-0.555, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2012, 3, 1), id=UUID('36be712f-f79f-4985-98ff-0318030e80d5'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=2.592, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2013, 3, 1), id=UUID('15407d7b-92d5-4841-9059-bf5d8628ac89'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.656, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2014, 3, 1), id=UUID('aa34a622-4fd4-46c6-a096-e3ffadf030e6'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.866, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2015, 3, 1), id=UUID('646696ad-8835-422b-bf5a-cad05138d323'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-0.489, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2016, 3, 1), id=UUID('bc6b9c8a-d2f0-4de3-81ea-65269ff62c80'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.253, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2017, 3, 1), id=UUID('ae874ab9-1838-4b71-a483-69f3bc1e9f2e'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=1.928, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2018, 3, 1), id=UUID('3925aa0c-04df-4c9a-b74f-b5b3bfe34d7b'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-2.235, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2019, 3, 1), id=UUID('27f5dc24-413b-4543-9cc6-d2ff7477f1b8'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.07, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2020, 3, 1), id=UUID('6396bde9-5c9b-4110-a158-c182b1ce0b33'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.189, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2021, 3, 1), id=UUID('e056a69c-1d1a-4eff-b658-33e9f193a3c9'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.764, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2022, 3, 1), id=UUID('bc45051d-a819-4c2b-adf1-5a8b9bf6e088'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=-1.408, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2023, 3, 1), id=UUID('2d58d4b6-3bc3-4c8f-8261-16fa3b3fe261'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.522, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35')),\n", - " MonthlyMeasurement(date=datetime.date(2024, 3, 1), id=UUID('588b9a27-3800-43cc-ac62-43a419368a91'), variable_id=UUID('32706ce0-0134-4122-91a0-9d6f237350b3'), value=0.739, station_id=UUID('8d9e6fe2-b79d-448f-bf33-b4a9d9b17e35'))]" + "[ConfigurationParameterValue(id=UUID('c2834ce6-b5a4-4ace-b569-b9a00a957413'), display_name_italian='Anno', description_italian=\"L'intero anno\", name='year', display_name_english='Year', description_english='Whole year', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('1021b1a8-9e9f-4c90-b483-9211bc17c2e0'), display_name_italian='Primavera', description_italian='Stagione climatologica primaverile (marzo, aprile, maggio)', name='MAM', display_name_english='Spring', description_english='Climatological spring season (March, April, May)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('731991b0-d6fd-48ad-976a-3519ee5e8e52'), display_name_italian='Estate', description_italian='Stagione climatologica estiva (giugno, luglio, agosto)', name='JJA', display_name_english='Summer', description_english='Climatological summer season (June, July, August)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('94b9b78b-e344-4288-a4e8-aa54f83ef63e'), display_name_italian='Autunno', description_italian='Stagione climatologica autunnale (settembre, ottobre, novembre)', name='SON', display_name_english='Autumn', description_english='Climatological autumn season (September, October, November)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", + " ConfigurationParameterValue(id=UUID('ff4e7c7b-7141-4d37-8979-3c5714ac4b4d'), display_name_italian='Inverno', description_italian='Stagione climatologica invernale (dicembre, gennaio, febbraio)', name='DJF', display_name_english='Winter', description_english='Climatological winter season (December, January, February)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767'))]" ] }, "execution_count": 12, @@ -190,7 +324,7 @@ } ], "source": [ - "[m for m in station.monthly_measurements if m.date.month in (1, 2, 3) and m.variable.name == \"TDd\"]" + "result[\"tas-annual-absolute\"][\"combinations\"][\"year_period\"][\"values\"]" ] } ], @@ -210,7 +344,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.10.14" } }, "nbformat": 4, From 26510d690d8d34d77b6a3f8771a8539998749519 Mon Sep 17 00:00:00 2001 From: Ricardo Garcia Silva Date: Mon, 2 Sep 2024 17:11:08 +0100 Subject: [PATCH 2/2] Provide an API endpoint for retrieving valid parameter combinations for forecasts This should be useful for building a navigation menu for clients --- arpav_ppcv/operations.py | 21 +--- arpav_ppcv/schemas/coverages.py | 13 ++ arpav_ppcv/webapp/api_v2/routers/coverages.py | 21 ++++ arpav_ppcv/webapp/api_v2/schemas/coverages.py | 111 +++++++++++++++++- tests/notebooks/generic.ipynb | 21 ++-- 5 files changed, 155 insertions(+), 32 deletions(-) diff --git a/arpav_ppcv/operations.py b/arpav_ppcv/operations.py index 431b1be5..880f6a6e 100644 --- a/arpav_ppcv/operations.py +++ b/arpav_ppcv/operations.py @@ -3,10 +3,7 @@ import io import logging import warnings -from typing import ( - Optional, - TypedDict, -) +from typing import Optional import anyio import cftime @@ -898,23 +895,9 @@ def _get_spatial_buffer( return transform(inverse_coordinate_transformer, buffer_geom_projected) -class ForecastVariableMenuTreeCombination(TypedDict): - configuration_parameter: coverages.ConfigurationParameter - values: list[coverages.ConfigurationParameterPossibleValue] - - -class ForecastVariableMenuTree(TypedDict): - climatological_variable: coverages.ConfigurationParameterPossibleValue - aggregation_period: coverages.ConfigurationParameterPossibleValue - measure: coverages.ConfigurationParameterPossibleValue - combinations: dict[str, ForecastVariableMenuTreeCombination] - - def get_forecast_variable_parameters( session: sqlmodel.Session, -) -> dict[str, ForecastVariableMenuTree]: - # - retrieve all the cov confs that have the variable - # - for each cov conf, aggregate by aggregation_period and measure +) -> dict[str, coverages.ForecastVariableMenuTree]: result = {} all_cov_confs = database.collect_all_coverage_configurations(session) for cov_conf in all_cov_confs: diff --git a/arpav_ppcv/schemas/coverages.py b/arpav_ppcv/schemas/coverages.py index 1c9e7bb0..98f16b9f 100644 --- a/arpav_ppcv/schemas/coverages.py +++ b/arpav_ppcv/schemas/coverages.py @@ -7,6 +7,7 @@ Optional, Final, TYPE_CHECKING, + TypedDict, ) import pydantic @@ -525,3 +526,15 @@ class CoverageInternal: def __hash__(self): return hash(self.identifier) + + +class ForecastVariableMenuTreeCombination(TypedDict): + configuration_parameter: ConfigurationParameter + values: list[ConfigurationParameterValue] + + +class ForecastVariableMenuTree(TypedDict): + climatological_variable: ConfigurationParameterValue + aggregation_period: ConfigurationParameterValue + measure: ConfigurationParameterValue + combinations: dict[str, ForecastVariableMenuTreeCombination] diff --git a/arpav_ppcv/webapp/api_v2/routers/coverages.py b/arpav_ppcv/webapp/api_v2/routers/coverages.py index 56ccd59a..f10a6bd6 100644 --- a/arpav_ppcv/webapp/api_v2/routers/coverages.py +++ b/arpav_ppcv/webapp/api_v2/routers/coverages.py @@ -552,3 +552,24 @@ def get_time_series( raise HTTPException(status_code=400, detail="Invalid coverage_identifier") else: raise HTTPException(status_code=400, detail="Invalid coverage_identifier") + + +@router.get( + "/variable-combinations", + response_model=coverage_schemas.ForecastVariableCombinationsList, +) +def get_variable_combinations( + db_session: Annotated[Session, Depends(dependencies.get_db_session)], +): + variable_combinations = operations.get_forecast_variable_parameters(db_session) + var_combinations = [] + for var_name, var_menu in variable_combinations.items(): + var_combinations.append( + coverage_schemas.VariableCombinations.from_items(var_menu) + ) + return coverage_schemas.ForecastVariableCombinationsList( + combinations=var_combinations, + translations=coverage_schemas.ForecastMenuTranslations.from_items( + list(variable_combinations.values()) + ), + ) diff --git a/arpav_ppcv/webapp/api_v2/schemas/coverages.py b/arpav_ppcv/webapp/api_v2/schemas/coverages.py index 0178eae0..b94f9848 100644 --- a/arpav_ppcv/webapp/api_v2/schemas/coverages.py +++ b/arpav_ppcv/webapp/api_v2/schemas/coverages.py @@ -4,7 +4,11 @@ import pydantic from fastapi import Request -from ....config import ArpavPpcvSettings +from ....config import ( + ArpavPpcvSettings, + LOCALE_EN, + LOCALE_IT, +) from ....schemas import coverages as app_models from .base import WebResourceList @@ -247,3 +251,108 @@ class ConfigurationParameterList(WebResourceList): items: list[ConfigurationParameterReadListItem] list_item_type = ConfigurationParameterReadListItem path_operation_name = "list_configuration_parameters" + + +class ConfigurationParameterMenuTranslation(pydantic.BaseModel): + name: dict[str, str] + description: dict[str, str] + + +class ForecastMenuTranslations(pydantic.BaseModel): + variable: dict[str, ConfigurationParameterMenuTranslation] + aggregation_period: dict[str, ConfigurationParameterMenuTranslation] + measure: dict[str, ConfigurationParameterMenuTranslation] + other_parameters: dict[str, dict[str, ConfigurationParameterMenuTranslation]] + + @classmethod + def from_items( + cls, variable_menu_trees: typing.Sequence[app_models.ForecastVariableMenuTree] + ): + result = {} + for variable_menu_tree in variable_menu_trees: + variable_cp = variable_menu_tree["climatological_variable"] + aggregation_period_cp = variable_menu_tree["aggregation_period"] + measure_cp = variable_menu_tree["measure"] + vars = result.setdefault("variable", {}) + vars[variable_cp.name] = ConfigurationParameterMenuTranslation( + name={ + LOCALE_EN.language: variable_cp.display_name_english, + LOCALE_IT.language: variable_cp.display_name_english, + }, + description={ + LOCALE_EN.language: variable_cp.description_english, + LOCALE_IT.language: variable_cp.description_italian, + }, + ) + aggreg_periods = result.setdefault("aggregation_period", {}) + aggreg_periods[ + aggregation_period_cp.name + ] = ConfigurationParameterMenuTranslation( + name={ + LOCALE_EN.language: aggregation_period_cp.display_name_english, + LOCALE_IT.language: aggregation_period_cp.display_name_english, + }, + description={ + LOCALE_EN.language: aggregation_period_cp.description_english, + LOCALE_IT.language: aggregation_period_cp.description_italian, + }, + ) + measures = result.setdefault("measure", {}) + measures[measure_cp.name] = ConfigurationParameterMenuTranslation( + name={ + LOCALE_EN.language: measure_cp.display_name_english, + LOCALE_IT.language: measure_cp.display_name_english, + }, + description={ + LOCALE_EN.language: measure_cp.description_english, + LOCALE_IT.language: measure_cp.description_italian, + }, + ) + others = result.setdefault("other_parameters", {}) + for combination_info in variable_menu_tree["combinations"].values(): + cp = combination_info["configuration_parameter"] + param_ = others.setdefault(cp.name, {}) + for cpv in cp.allowed_values: + param_[cpv.name] = ConfigurationParameterMenuTranslation( + name={ + LOCALE_EN.language: cpv.display_name_english, + LOCALE_IT.language: cpv.display_name_english, + }, + description={ + LOCALE_EN.language: cpv.description_english, + LOCALE_IT.language: cpv.description_italian, + }, + ) + return cls( + variable=result["variable"], + aggregation_period=result["aggregation_period"], + measure=result["measure"], + other_parameters=result["other_parameters"], + ) + + +class VariableCombinations(pydantic.BaseModel): + variable: str + aggregation_period: str + measure: str + other_parameters: dict[str, list[str]] + + @classmethod + def from_items(cls, menu_tree: app_models.ForecastVariableMenuTree): + combinations = {} + for param_name, param_combinations in menu_tree["combinations"].items(): + combinations[param_name] = [] + for valid_value in param_combinations["values"]: + combinations[param_name].append(valid_value.name) + + return cls( + variable=menu_tree["climatological_variable"].name, + aggregation_period=menu_tree["aggregation_period"].name, + measure=menu_tree["measure"].name, + other_parameters=combinations, + ) + + +class ForecastVariableCombinationsList(pydantic.BaseModel): + combinations: list[VariableCombinations] + translations: ForecastMenuTranslations diff --git a/tests/notebooks/generic.ipynb b/tests/notebooks/generic.ipynb index 6fe02b08..3d466cc4 100644 --- a/tests/notebooks/generic.ipynb +++ b/tests/notebooks/generic.ipynb @@ -134,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "97e789b2-721b-4e10-baa4-8b4bb39d3ade", "metadata": {}, "outputs": [ @@ -196,17 +196,17 @@ }, { "cell_type": "code", - "execution_count": 6, - "id": "dd151151-4344-42e3-8a19-d2a6ad6d252a", + "execution_count": 8, + "id": "646bf16d-7858-424e-af2b-73dbd30413db", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "ConfigurationParameterValue(id=UUID('e6ff2bf7-67c4-48f9-ad3a-e0737cc2c07a'), display_name_italian='TAS', description_italian='Temperatura media', name='tas', display_name_english='TAS', description_english='Mean temperature', configuration_parameter_id=UUID('12dfb711-9c18-46ac-8fc5-0b902eb48964'))" + "ConfigurationParameterValue(id=UUID('e6ff2bf7-67c4-48f9-ad3a-e0737cc2c07a'), display_name_italian='TAS', description_italian='Temperatura media', display_name_english='TAS', name='tas', description_english='Mean temperature', configuration_parameter_id=UUID('12dfb711-9c18-46ac-8fc5-0b902eb48964'))" ] }, - "execution_count": 6, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -280,26 +280,23 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "id": "9672f748-b3d4-48a1-b2f7-f0c60ec4f9d4", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[ConfigurationParameterValue(id=UUID('1021b1a8-9e9f-4c90-b483-9211bc17c2e0'), display_name_italian='Primavera', description_italian='Stagione climatologica primaverile (marzo, aprile, maggio)', name='MAM', display_name_english='Spring', description_english='Climatological spring season (March, April, May)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", - " ConfigurationParameterValue(id=UUID('731991b0-d6fd-48ad-976a-3519ee5e8e52'), display_name_italian='Estate', description_italian='Stagione climatologica estiva (giugno, luglio, agosto)', name='JJA', display_name_english='Summer', description_english='Climatological summer season (June, July, August)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", - " ConfigurationParameterValue(id=UUID('94b9b78b-e344-4288-a4e8-aa54f83ef63e'), display_name_italian='Autunno', description_italian='Stagione climatologica autunnale (settembre, ottobre, novembre)', name='SON', display_name_english='Autumn', description_english='Climatological autumn season (September, October, November)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767')),\n", - " ConfigurationParameterValue(id=UUID('ff4e7c7b-7141-4d37-8979-3c5714ac4b4d'), display_name_italian='Inverno', description_italian='Stagione climatologica invernale (dicembre, gennaio, febbraio)', name='DJF', display_name_english='Winter', description_english='Climatological winter season (December, January, February)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767'))]" + "ConfigurationParameterValue(id=UUID('ff4e7c7b-7141-4d37-8979-3c5714ac4b4d'), display_name_italian='Inverno', description_italian='Stagione climatologica invernale (dicembre, gennaio, febbraio)', display_name_english='Winter', name='DJF', description_english='Climatological winter season (December, January, February)', configuration_parameter_id=UUID('1f0a6946-ae9a-48d8-81ef-ef18b14ac767'))" ] }, - "execution_count": 10, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "result[\"tas-30yr-anomaly\"][\"combinations\"][\"year_period\"][\"values\"]" + "result[\"tas-30yr-anomaly\"][\"combinations\"][\"year_period\"][\"configuration_parameter\"].allowed_values[0]" ] }, {