diff --git a/PSILARTEMP.py b/PSILARTEMP.py index 6f7158ad563975e7872c36a894bd0b3caecf2d64..3edc985aa319ed12637c93fd282ab8032fc0e613 100755 --- a/PSILARTEMP.py +++ b/PSILARTEMP.py @@ -18,6 +18,8 @@ import subprocess import os +import sys +import shutil from dotenv import load_dotenv from datetime import datetime import pytz @@ -31,24 +33,34 @@ load_dotenv() config = configparser.ConfigParser() config.read("PSILARTEMP.cfg") -year = os.getenv("YEAR") +local_timezone = pytz.timezone(os.getenv("LOCAL_TIMEZONE")) +today = datetime.now(local_timezone) +if len(sys.argv) > 1: + year = int(sys.argv[1]) +else: + year = today.year + recurring_start_date = os.getenv("RECURRING_START_DATE") -weatherdata_path = os.getenv("WEATHER_DATA_DIR") +weatherdata_path = f'{os.getenv("WEATHER_DATA_DIR")}{year}/' tmp_path = "tmp/" -out_path = os.getenv("DATA_DIR") +home_dir = os.getenv("HOME_DIR") +out_path = f'{os.getenv("DATA_DIR")}{year}/' +os.makedirs(out_path, exist_ok=True) -# TODO: Put timezone out in .env -local_timezone = pytz.timezone("Europe/Oslo") +# Ensure that model is not run for future year +if year > today.year: + print(f"Cannot run model for future year ({year}). Quit.") + exit(0) # If we are before the recurring start date, exit nicely -start_time = datetime.strptime(f"{year}-{recurring_start_date}","%Y-%m-%d") -if datetime.now() <= start_time: - print(f"Today is before the configured start time of {start_time}. Exiting.") +start_time = local_timezone.localize(datetime.strptime(f"{year}-{recurring_start_date}","%Y-%m-%d")) +if today <= start_time: + print(f"Today is before the configured model start {start_time}. Exiting.") exit(0) # """ -# Calculate cumulated degree days above 5 degrees after 1st of April -# Remove all values before April 1st +# Calculate cumulated degree days above 5 degrees after 1st of March +# Remove all values before March 1st subprocess.run( f"cdo -selname,TM -seldate,{year}-{recurring_start_date}T00:00:00,{year}-12-31T00:00:00 {weatherdata_path}met_1_0km_nordic-{year}.nc {tmp_path}TM_from_april.nc", shell=True, @@ -108,15 +120,15 @@ timesteps = result.variables["time"][:] # print(timesteps) timestep_index = 1 timestep_dates = [] + +# Remove existing tif files from result folder +subprocess.run(f"rm {out_path}result_*{year}*.tif", shell=True) + for timestep in timesteps: timestep_date = datetime.fromtimestamp(timestep).astimezone(local_timezone) file_date = timestep_date.astimezone(local_timezone).strftime("%Y-%m-%d") # 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: subprocess.run( f'gdal_translate -ot Int16 -of GTiff -b {timestep_index} NETCDF:"{tmp_path}result.nc":WARNING_STATUS {tmp_path}result_WARNING_STATUS_{file_date}_lcc.tif', @@ -165,8 +177,8 @@ template = env.get_template("mapfile/template.j2") output = template.render( { "timestep_dates": timestep_dates, - "mapserver_data_dir": os.getenv("MAPSERVER_DATA_DIR"), - "mapserver_mapfile_dir": os.getenv("MAPSERVER_MAPFILE_DIR"), + "mapserver_data_dir": f"{os.getenv('MAPSERVER_DATA_DIR')}{year}/", + "mapserver_mapfile_dir": f"{os.getenv('MAPSERVER_MAPFILE_DIR')}{year}/", "mapserver_log_file": os.getenv("MAPSERVER_LOG_FILE"), "mapserver_image_path": os.getenv("MAPSERVER_IMAGE_PATH"), "mapserver_extent": os.getenv("MAPSERVER_EXTENT"), @@ -174,6 +186,18 @@ output = template.render( "language_codes": language_codes, } ) -mapfile_outdir = os.getenv("MAPFILE_DIR") -with open(f"{mapfile_outdir}/PSILARTEMP.map", "w") as f: + +# Remove temporary files +subprocess.run(f"rm {tmp_path}*.tif", shell=True) +subprocess.run(f"rm {tmp_path}*.nc", shell=True) + +mapfile_outdir = f'{os.getenv("MAPFILE_DIR")}{year}/' +os.makedirs(mapfile_outdir, exist_ok=True) + +query_template = os.path.join(home_dir, "mapfile/query_template.xml") +query_template_DD = os.path.join(home_dir, "mapfile/query_template_DD.xml") +shutil.copy(query_template, mapfile_outdir) +shutil.copy(query_template_DD, mapfile_outdir) + +with open(f"{mapfile_outdir}PSILARTEMP.map", "w") as f: f.write(output) diff --git a/README.md b/README.md index 997d4db6e127513d88807e6e57f07a57603c024c..79ff7721de9931921541507fe5cf5bb8e99e309c 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,12 @@ The model (as per 2023-11-14) assumes that a weather data file named `met_1_0km_ It is required that you have set the following environment variables: ```bash -YEAR=2024 # Recurring start date (MM-DD) RECURRING_START_DATE=04-01 +# Local time zone +LOCAL_TIMEZONE=Europe/Oslo # Where your application resides -HOME_DIR=/home/foo/ +HOME_DIR=/home/foo/PSILARTEMP/ # Path to the weather data WEATHER_DATA_DIR=in/ # Path to optional CSV file with polygons for masking result. @@ -71,12 +72,12 @@ MAPSERVER_EXTENT="-1.5831861262936526 52.4465003983706595 39.2608060398730458 71 ```bash $ ./run_PSILARTEMP.sh ``` -This creates a Python virtualenv, installs all the Python dependencies, runs the model and stores output in a log file. +This creates a Python virtualenv, installs all the Python dependencies, runs the model and stores output in a log file. -Alternatively, primarily for development purposes, you can run the Python script PSILARTEMP directly: +The script can be run for a specific year like this: ```bash -$ ./PSILARTEMP.py +$ ./run_PSILARTEMP.sh 2024 ``` All intermediary files are stored in the `tmp/` folder, and they are all deleted when the model is done calculating. The GeoTIFF files are stored in the `out/` folder, and the generated mapfile is stored in the `mapfile/` folder @@ -183,4 +184,4 @@ else // Fallback to auto generated legend { document.getElementById("layerLegend").innerHTML='<img id="layerLegendImg" src="' + currentLayer.Style[0].LegendURL[0].OnlineResource + '"/>'; } -``` \ No newline at end of file +``` diff --git a/env-sample b/env-sample index e0f2cad3d82eff856d6ae045a5d097f0680e5ff2..0e993577f4fe5d66c6c3c240befcc9be9e06ce04 100644 --- a/env-sample +++ b/env-sample @@ -1,11 +1,11 @@ # Use this as an example to create your own .env file -# Year to run for -YEAR=2024 # Recurring start date (MM-DD) RECURRING_START_DATE=04-01 +# Local time zone +LOCAL_TIMEZONE=Europe/Oslo # Where your application resides -HOME_DIR=/home/foo/ +HOME_DIR=/home/foo/PSILARTEMP/ # Path to the weather data WEATHER_DATA_DIR=in/ # Path to optional CSV file with polygons for masking result. @@ -23,4 +23,4 @@ MAPSERVER_LOG_FILE=/foo/log/PSILARTEMP.log # Path to the temporary directory for writing temporary files and images. Must be writable by the user the web server is running as MAPSERVER_IMAGE_PATH=/foo/mapserver/tmp/ # The value of the EXTENT parameter in Mapserver's mapfile. Units are DD (Decimal degrees) -MAPSERVER_EXTENT="-1.5831861262936526 52.4465003983706595 39.2608060398730458 71.7683216082912736" \ No newline at end of file +MAPSERVER_EXTENT="-1.5831861262936526 52.4465003983706595 39.2608060398730458 71.7683216082912736" diff --git a/run_PSILARTEMP.sh b/run_PSILARTEMP.sh index 9b2c45642e732ea431476d3f5e11e58ef2f11e82..8e3dadb7ac713ba377d56f078a9e668c83ced0ca 100755 --- a/run_PSILARTEMP.sh +++ b/run_PSILARTEMP.sh @@ -18,9 +18,25 @@ # Configures environment and logging before running the model # @author: Tor-Einar Skog <tor-einar.skog@nibio.no> +validate_year() { + if [[ $1 =~ ^[0-9]{4}$ ]]; then + return 0 + else + return 1 + fi +} +# Check if the year parameter is passed and validate it +if [ -n "$1" ]; then + if validate_year "$1"; then + year=$1 + else + echo "Invalid year: $1. Please provide a valid 4-digit year." + exit 1 + fi +fi -# First: Test that we have CDO and GDAL installed +# Test that we have CDO and GDAL installed if ! command -v cdo &> /dev/null then echo "ERROR: CDO could not be found. Exiting." @@ -44,11 +60,10 @@ then fi # Paths to scripts and requirements -APP_PATH=${HOME_DIR}PSILARTEMP/ -LOG_FILE=${APP_PATH}log/PSILARTEMP.log -REQUIREMENTS=${APP_PATH}requirements.txt +LOG_FILE=${HOME_DIR}log/PSILARTEMP.log +REQUIREMENTS=${HOME_DIR}requirements.txt -cd $APP_PATH +cd $HOME_DIR # Create and activate the virtual environment python3 -m venv .venv @@ -57,9 +72,16 @@ python3 -m pip install -q --upgrade pip pip install -q -r $REQUIREMENTS # Run the model -echo "==== `date`: Running model" &>> "$LOG_FILE" -python3 $APP_PATH/PSILARTEMP.py &>> "$LOG_FILE" -echo "==== `date`: DONE running model" &>> "$LOG_FILE" + +if [ -z "${year}" ]; then + echo "==== $(date): Running model for current year" >> "$LOG_FILE" 2>&1 + python3 ${HOME_DIR}PSILARTEMP.py >> "$LOG_FILE" 2>&1 +else + echo "==== $(date): Running model for ${year}" >> "$LOG_FILE" 2>&1 + python3 ${HOME_DIR}PSILARTEMP.py "$year" >> "$LOG_FILE" 2>&1 +fi + +echo "==== $(date): Done running model" >> "$LOG_FILE" 2>&1 # Deactivate the virtual environment deactivate