diff --git a/PSILARTEMP.cfg b/PSILARTEMP.cfg new file mode 100644 index 0000000000000000000000000000000000000000..3eb9b6e5c09347a58f907d9d37fde7d2ec626ce8 --- /dev/null +++ b/PSILARTEMP.cfg @@ -0,0 +1,15 @@ +[i18n] +# 1st is the default language +languages=en,nb + +[i18n.en] +no_forecast = No forecast +no_risk = No risk +possible_risk = Possible risk +high_risk = High risk + +[i18n.nb] +no_forecast = Varsel beregnes ikke +no_risk = Ingen infeksjonsrisikok +possible_risk = Mulig fare for angrep +high_risk = Høy fare for angrep \ No newline at end of file diff --git a/PSILARTEMP.py b/PSILARTEMP.py index 7bb0a2215b6ff46a0cd815e0da5a78944daeb5b2..574bb4b9050efaf01247c6c081e8bc346b04fa25 100755 --- a/PSILARTEMP.py +++ b/PSILARTEMP.py @@ -21,9 +21,14 @@ from dotenv import load_dotenv from datetime import datetime import pytz import netCDF4 as nc +import configparser from jinja2 import Environment, FileSystemLoader +# Load deployment specific settings load_dotenv() +# Get language stuff +config = configparser.ConfigParser() +config.read("PSILARTEMP.cfg") weatherdata_path = os.getenv("WEATHER_DATA_DIR") tmp_path = "tmp/" @@ -33,7 +38,7 @@ out_path = os.getenv("DATA_DIR") utc_offset = "+02:00" local_timezone = pytz.timezone("Europe/Oslo") - +""" # Calculate cumulated degree days above 5 degrees after 1st of April # Remove all values before April 1st subprocess.run(f"cdo -selname,TM -seldate,2023-04-01T00:00:00,2023-12-31T00:00:00 {weatherdata_path}met_1_0km_nordic-2023.nc {tmp_path}TM_from_april.nc", shell=True) @@ -61,6 +66,8 @@ else: # (A>0)*(A<=260)*2 + (A>260)*(A<=360)*3 + (A>360)*(A<=560)*4 + (A>560)*0 subprocess.run(f'cdo -aexpr,"WARNING_STATUS=(TM>0)*(TM<=260)*2 + (TM>260)*(TM<=360)*3 + (TM>360)*(TM<=560)*4 + (TM>560)*0" {tmp_path}DD.nc {tmp_path}result.nc', shell=True) +""" + # Split the combined file into daily .nc files again, with YYYY-MM-DD in the filename. Convert to corresponding GeoTIFF files # Variables that needs discrete classification, must be integers in order for mapserver to work properly (Don't ask!) # Since we need WARNING_STATUS to be discretely classified, we need to create a separate GeoTIFF file for it @@ -75,6 +82,7 @@ for timestep in timesteps: #print(f"{timestep_index}: {file_date}") timestep_dates.append(file_date) # We must delete the GeoTIFF file before merging + """ subprocess.run(f'rm {tmp_path}result_*{file_date}_lcc.tif', shell=True) subprocess.run(f'rm {out_path}result_*{file_date}.tif', shell=True) with open("/dev/null", "w") as devnull: @@ -83,6 +91,7 @@ for timestep in timesteps: # Need to reproject the files, to ensure we have the projection given in the generted mapfile. We always use EPSG:4326 for this subprocess.run(f'gdalwarp -t_srs EPSG:4326 {tmp_path}result_WARNING_STATUS_{file_date}_lcc.tif {out_path}result_WARNING_STATUS_{file_date}.tif', shell=True, stdout=devnull) subprocess.run(f'gdalwarp -t_srs EPSG:4326 {tmp_path}result_{file_date}_lcc.tif {out_path}result_{file_date}.tif', shell=True, stdout=devnull) + """ timestep_index = timestep_index + 1 if len(timestep_dates) != len(set(timestep_dates)): @@ -92,6 +101,15 @@ if len(timestep_dates) != len(set(timestep_dates)): #print(len(timestep_dates)) # Generate mapfile +# Building data sets for language specific legends +languages = [] +for language_code in config["i18n"]["languages"].split(","): + language = {"language_code": language_code} + if ("i18n.%s" % language_code) in config: + for keyword in config["i18n.%s" % language_code]: + language[keyword] = config["i18n.%s" % language_code][keyword] + languages.append(language) + # The paths should be set in a .env file env = Environment(loader=FileSystemLoader('.')) template = env.get_template("mapfile/template.j2") @@ -101,7 +119,8 @@ output = template.render({ "mapserver_mapfile_dir": os.getenv("MAPSERVER_MAPFILE_DIR"), "mapserver_log_file": os.getenv("MAPSERVER_LOG_FILE"), "mapserver_image_path": os.getenv("MAPSERVER_IMAGE_PATH"), - "mapserver_extent": os.getenv("MAPSERVER_EXTENT") + "mapserver_extent": os.getenv("MAPSERVER_EXTENT"), + "languages": languages }) mapfile_outdir = os.getenv("MAPFILE_DIR") with open(f"{mapfile_outdir}/PSILARTEMP.map", 'w') as f: diff --git a/mapfile/template.j2 b/mapfile/template.j2 index f5afaa02103c80e995ea91d699ef3738007e59f6..2af9992bab6b3b3c64dd8a63571fa55026e5341a 100644 --- a/mapfile/template.j2 +++ b/mapfile/template.j2 @@ -35,8 +35,34 @@ WEB # List of standard metadata: https://mapserver.org/ogc/wms_server.html#web-object-metadata # i18n support: https://mapserver.org/ogc/inspire.html#inspire-multi-language-support METADATA + "wms_inspire_capabilities" "embed" + "wms_languages" "en,nb" # The first is the default "wms_keywordlist" "VIPS model Carrot Rust Fly (PSILARTEMP)" - "wms_abstract" " + "wms_abstract.nb" " + <h2>Modellbeskrivelse</h2> + <p>Varslingsmodellen «Gulrotflue svermetidspunkt» er basert på en finsk, temperaturbasert modell (Markkula <em>et al</em>, 1998; Tiilikkala & Ojanen, 1999; Markkula <em>et al</em>, 2000). Modellen beregner tidspunkt for sverming av 1. generasjon og 2. generasjon av gulrotflue basert på akkumulering av graddager (døgngrader) over en basistemperatur på 5 °C. I VIPS benyttes modellen kun for 1. generasjon.</p> + <p>Det er standard lufttemperatur (temperatur målt 2 m over bakken) som benyttes i modellen. Graddager er her definert som summen av differansen mellom en basistemperatur på 5 °C og døgnmiddeltemperatur for alle døgn med temperatur >5 °C dvs. summen av (døgnmiddeltemperatur - 5 °C) fra 1. mars (fra det er telefritt i jorda).</p> + <h2>Tolking av varsel</h2> + <p>Grønne bokser betyr at svermingen enda ikke har begynt. Akkumulering av døgngrader er < 260 graddager (døgngrader).</p> + <p>Gule bokser betyr svermingen er i startfasen og at man må være obs på at det kan komme innflyvere i åkeren. Akkumulering av døgngrader er ≥ 260 graddager (døgngrader).</p> + <p>Røde bokser betyr svermingen er på sitt mest aktive. Akkumulering av døgngrader er ≥ 360 graddager (døgngrader).</p> + <p>Grå bokser betyr at svermingen av 1. generasjon er over og varslingen er avsluttet. Akkumulering av døgngrader er ≥ 560 graddager (døgngrader).</p> + <p>Vær klar over at i områder med dekke (plast, enkel og dobbel fiberduk el. lign.) ved tidligproduksjon (enten på samme jorde eller nabojorder) året før, kan svermingen starte tidligere på grunn av høyere jordtemperatur under dekket.</p> + <h2>Varslingssesong – oppstart og avslutning av varsel</h2> + <p>Starttidspunkt: Vises i VIPS fra 1. april (startdato for akkumulering av graddager fra det er telefritt) i jorda.</p> + <p>Sluttidspunkt: Når modellen har nådd kravet til døgngrader for avsluttet sverming av 1. generasjon (560 døgngrader).</p> + <h2>Utprøving og validering av modellen</h2> + <h3>Nasjonalt</h3> + <p>Modellen har vært testet og evaluert for norske forhold i perioden 2011-2015. Valideringen har vist at modellen stemte ganske bra for de fleste steder for 1. generasjon. Modellen stemte imidlertid dårlig for 2. generasjon for mange lokaliteter og var direkte feil for Jæren-distriktet. På bakgrunn av resultatene fra valideringen har vi derfor valgt å fjerne varsling av 2. generasjon gulrotflue med denne modellen.</p> + <h3>Internasjonalt</h3> + <p>Modellen er i bruk i Finland. Det er usikkert hvor omfattende modellen er validert i Finland, men det er utført en validering sommeren 1997. Denne valideringen tilsa at modellen stemte nokså bra, men at terskeltemperatursummen burde reduseres til 255 graddager for svermingsstart (mot 260 graddager i den opprinnelige modellen) og 355 graddager for svermetoppen (mot 360 daggrader i den opprinnelige modellen) (Tiilikkala & Ojanen, 1999).</p> + <h2>Referanser</h2> + <ul> + <li>Markkula, I., H. Ojanen and K. Tiilikkala. 1998. Forecasting and monitoring of the carrot fly (Psila rosae) in Finland. The 1998 Brighton Conference: Pests and Diseases: Conference Proceedings, Volume 2, pages 657-662.</li> + <li>Tiilikkala, K. and H. Ojanen. 1999. Use of a geographical information system (GIS) for forecasting the activities of carrot fly and cabbage root fly. IOBC/WPRS Bulletin 22 (5): 15-24.</li> + <li>Markkula, I., A. Hannukkala, A. Lehtinen, I. Mattila, H. Ojanen, S. Raisjio, P. Reijonen and K. Tiilikkala. 2000. Pest warnings and forecasts sent as SMS messages from models into "farmer's pocket". In publication: Pests & Diseases 2000. Proceedings of an international conference held at the Brighton Hilton Metropole Hotel, UK, 13-16 November 2000. BCPC Conference Proceedings pages 285-290.</li> + " + "wms_abstract.en" " <p>The warning system model «Carrot rust fly temperature» is based on a Finnish temperature-based model (Markkula <em>et al</em>, 1998; Tiilikkala & Ojanen, 1999; Markkula <em>et al</em>, 2000). The model determines the start of the flight period for the 1st and 2nd generation of carrot rust fly based on accumuleted degree-days (day-degrees) over a base temperature of 5,0 °C. VIPS uses the model for the 1st generation only.</p> <p>Standard air temperature (temperature measured 2 m above ground) is used in the model. Degree-days are defined for this model as the sum of the difference between a base temperature of 5,0 °C and the mean temperature for all days with a temperature >5,0 °C, in other words (daily mean temperature – 5,0 °C) from 1 March (beginning when the ground has thawed).</p> <h3>Interpretation of the warning</h3> @@ -62,7 +88,8 @@ WEB <p>Annette Folkedal Schjøll <a href=\"mailto:annette.folkedal.schjoll@nibio.no\">annette.folkedal.schjoll@nibio.no</a><br />Tor J. Johansen <a href=\"mailto:tor.johansen@nibio.no\">tor.johansen@nibio.no</a></p> " "wms_enable_request" "*" - "wms_title" "Carrot rust fly (Psila rosae) temperature model" + "wms_title.en" "Carrot rust fly (Psila rosae) temperature model" + "wms_title.nb" "Gulrotflue svermetidspunktmodell" "wms_getfeatureinfo_formatlist" "text/plain,text/html,text/xml" "wms_accessconstraints" "none" "wms_addresstype" "" @@ -104,7 +131,17 @@ LAYER STATUS ON METADATA - "wms_title" "Carrot rust fly (Psila rosae) temperature model {{ timestep_date }}" + "wms_title" "Carrot rust fly (Psila rosae) temperature model {{ timestep_date }}" + {% for language in languages %} + "wms_abstract.{{language.language_code}}" " + <ul style=\"list-style: none; padding: 0;\"> + <li style=\"margin-bottom: 5px;\"><span style=\"background-color: #707070;\"> </span> {{language.no_forecast}}</li> + <li style=\"margin-bottom: 5px;\"><span style=\"background-color: #00B457;\"> </span> {{language.no_risk}}</li> + <li style=\"margin-bottom: 5px;\"><span style=\"background-color: #FFCC00;\"> </span> {{language.possible_risk}}</li> + <li><span style=\"background-color: #FF0000;\"> </span> {{language.high_risk}}</li> + </ul> + " + {% endfor %} END CLASSITEM "[pixel]"