#!/usr/bin/env python3 # # src_back.py --- Backward versus Forward Dispersion # See HYSPLIT Tutorial Sec. 13.2 # # Change history: # 18 Oct 2025 (BB) - standard-aligned, cross-platform version # 12 Feb 2026 (SZ) - minor edits for style consistency # 18 Jun 2026 (SZ) - standardize code for run_cmd(), convert_html_to_img(), # etc. across Python scripts # - ensure encoding is specified when opening files import os import sys import platform from pathlib import Path import subprocess if sys.version_info < (3, 8): print("Please use Python 3.8 or higher.") sys.exit(1) system = platform.system().lower() if system == "windows": PGM = Path(sys.argv[1]) if len(sys.argv) > 1 else Path("C:\\hysplit") OUT = Path(sys.argv[2]) if len(sys.argv) > 2 else PGM / "working" DSP = sys.argv[3] if len(sys.argv) > 3 else "YES" TTR = Path(os.environ.get("TTR", "C:\\Tutorial")) exe_suffix = ".exe" else: PGM = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.home() / "hysplit" OUT = Path(sys.argv[2]) if len(sys.argv) > 2 else PGM / "working" DSP = sys.argv[3] if len(sys.argv) > 3 else "YES" TTR = Path(os.environ.get("TTR", Path.home() / "tutorial")) exe_suffix = "" if not PGM.exists(): script = Path(__file__).name if "__file__" in globals() else "src_back.py" print(f"ERROR: HYSPLIT not found at {PGM}") print(f""" Please specify the path to your HYSPLIT installation using a command-line argument: python {script} YOUR_HYSPLIT_DIRECTORY [OUT] [DSP (YES|NO)] Example: python {script} C:\\hysplit C:\\hysplit\\working YES """) sys.exit(1) if not TTR.exists(): print(f"ERROR: HYSPLIT tutorial not found at {TTR}") print(""" Please set the TTR environment variable to point to your HYSPLIT tutorial directory. For Windows users (Command Prompt): SET TTR=YOUR_HYSPLIT_TUTORIAL_DIRECTORY For Linux users (bash shell): export TTR='YOUR_HYSPLIT_TUTORIAL_DIRECTORY' For Linux users (csh or tcsh shell): setenv TTR 'YOUR_HYSPLIT_TUTORIAL_DIRECTORY'""") sys.exit(1) os.chdir(OUT) # ------------------------------------------------------------------ # Helper function # ------------------------------------------------------------------ def run_cmd(cmd, desc="", allow_fail=False, stdout_file=None, append=False): if desc: print(f"{desc}...") exitcode = 0 with subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) as p: if stdout_file: mode="a" if append else "w" with open(stdout_file, mode, encoding="utf-8") as f_out: for ln in p.stdout: print(ln, end="") f_out.write(ln) else: with p.stdout as f: for ln in iter(f.readline, b'\n'): if len(ln) == 0: break print(ln.rstrip()) done = False while not done: try: exitcode = p.wait(timeout=1) done = True except subprocess.TimeoutExpired: print("WARN: subprocess timed out.") if exitcode != 0: if allow_fail: print(f"WARN: command failed with exit code {exitcode} -> {' '.join(cmd)}") else: print(f"ERROR: command failed with exit code {exitcode} -> {' '.join(cmd)}") sys.exit(1) # ------------------------------------------------------------------- # static inputs # ------------------------------------------------------------------- wrk = TTR met_dir = wrk / "captex" met_file = "captex2_wrf27uw.bin" top = 10000.0 lvl = 10.0 # ------------------------------------------------------------------- # ASCDATA.CFG # ------------------------------------------------------------------- with open("ASCDATA.CFG", "w", encoding="ascii") as f: f.write( "-90.0 -180.0\n" "1.0 1.0\n" "180 360\n" "2\n" "0.2\n" f"'{PGM / 'bdyfiles'}{os.sep}' directory of files\n" ) def write_setup(): with open("SETUP.CFG", "w", encoding="ascii") as f: f.write("&SETUP\n") f.write(" numpar = 50000,\n") f.write(" maxpar = 100000,\n") f.write("/\n") def write_control( syr, smo, sda, shr, lat, lon, run_hours, inp, start_time, end_time ): with open("CONTROL", "w", encoding="ascii") as f: f.write(f"{syr} {smo} {sda} {shr}\n") f.write("1\n") f.write(f"{lat} {lon} {lvl}\n") f.write(f"{run_hours}\n") f.write("0\n") f.write(f"{top}\n") f.write("1\n") f.write(f"{met_dir}{os.sep}\n") f.write(f"{met_file}\n") f.write("1\n") f.write("PMCH\n") f.write("1.0\n") f.write("1.0\n") f.write("00 00 00 00 00\n") f.write("1\n") f.write("42.0 -78.0\n") f.write("0.25 0.25\n") f.write("15.0 25.0\n") f.write(f".{os.sep}\n") f.write(f"{inp}\n") f.write("1\n") f.write("100\n") f.write(f"{start_time}\n") f.write(f"{end_time}\n") f.write("00 01 00\n") f.write("1\n") f.write("0.0 0.0 0.0\n") f.write("0.0 0.0 0.0 0.0 0.0\n") f.write("0.0 0.0 0.0\n") f.write("0.0\n") f.write("0.0\n") def run_hycs(inp): if Path(inp).exists(): Path(inp).unlink() write_setup() run_cmd( [str(PGM / "exec" / f"hycs_std{exe_suffix}")], "Running hycs_std" ) def run_con2stn(inp, station_lat, station_lon, outfile): with open("samplers.txt", "w", encoding="ascii") as f: f.write(f"S316 {station_lat} {station_lon}\n") run_cmd([ str(PGM / "exec" / f"con2stn{exe_suffix}"), "-xn", f"-i{inp}", f"-o{outfile}", "-r1", "-c1.0E+15", "-ssamplers.txt" ], "Running con2stn") with open(outfile, "r", encoding="ascii", errors="ignore") as f: print(f.read()) Path("samplers.txt").unlink() # ------------------------------------------------------------------- # FORWARD RUN # ------------------------------------------------------------------- inp = "hysp_fwrd.bin" write_control( syr=83, smo=9, sda=25, shr=17, lat=39.90, lon=-84.22, run_hours=19, inp=inp, start_time="83 09 25 17 00", end_time="83 09 28 15 00" ) run_hycs(inp) run_con2stn(inp, 41.30, -82.22, "con2stn_bak1.txt") if DSP.upper() == "YES": input("Press Enter to continue...") # ------------------------------------------------------------------- # BACKWARD RUN # ------------------------------------------------------------------- inp = "hysp_back.bin" write_control( syr=83, smo=9, sda=26, shr=8, lat=41.30, lon=-82.22, run_hours=-15, inp=inp, start_time="83 09 26 08 00", end_time="83 09 25 17 00" ) run_hycs(inp) run_con2stn(inp, 39.90, -84.22, "con2stn_bak2.txt")