#!/usr/bin/env python3 # # test_inputs.py --- Test and Optimize Input Files # See HYSPLIT Tutorial Sec. 8.5 # # Change history: # 17 Jun 2026 (SZ) - initial # 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 import subprocess from pathlib import Path # Version check 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 "test_inputs.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_TOTURIAL_DIRECTORY' For Linux users (csh or tcsh shell): setenv TTR 'YOUR_HYSPLIT_TOTURIAL_DIRECTORY'""") sys.exit(1) os.chdir(OUT) # ------------------------------------------------------------------ # Helper functions # ------------------------------------------------------------------ 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) # Build ASCDATA.CFG with open("ASCDATA.CFG", "w", encoding="ascii") as f: f.write("-90.0 -180.0 lat/lon of lower left corner\n") f.write("1.0 1.0 lat/lon spacing in degrees\n") f.write("180 360 lat/lon number of data points\n") f.write("2 default land use category\n") f.write("0.2 default roughness length (m)\n") f.write(f"'{PGM / 'bdyfiles'}{os.sep}' directory of files\n") # CONTROL file syr, smo, sda, shr = 83, 9, 25, 17 lat, lon, lvl = 39.90, -84.22, 10.0 run, top = 68, 10000.0 metdir = TTR / "captex" metfile = "captex2_wrf27uw.bin" control_lines = [ f"{syr} {smo} {sda} {shr}", "1", f"{lat} {lon} {lvl}", f"{run}", "0", f"{top}", "1", f"{metdir}{os.sep}", metfile, "1", "PMCH", "67000.0", "3.0", "00 00 00 00 00", "1", "42.0 -78.0", "0.25 0.25", "15.0 25.0", "./", "hysplit2.bin", "1", "100", "83 09 25 18 00", "83 09 28 15 00", "00 03 00", "1", "0.0 0.0 0.0", "0.0 0.0 0.0 0.0 0.0", "0.0 0.0 0.0", "0.0", "0.0", ] with open("CONTROL", "w", encoding="ascii") as f: for line in control_lines: f.write(line + "\n") # SETUP.CFG with open("SETUP.CFG", "w", encoding="ascii") as f: f.write("&SETUP\n") f.write(" numpar = 2500,\n") f.write(" maxpar = 100000,\n") f.write(" ndump = 1,\n") f.write(" ncycl = 3,\n") f.write("/\n") # Run a test run_cmd( [str(PGM / "exec" / f"hysptest{exe_suffix}")], "Running hysptest" ) # Run model for fn in ("CONTROL", "SETUP.CFG"): if Path(fn).exists(): Path(fn).unlink() os.rename("CONTROL_mod", "CONTROL") os.rename("SETUP_mod.CFG", "SETUP.CFG") input("SETUP and CONTROL modified, enter to run HYSPLIT...") fn = OUT / "hysplit2.bin" if fn.exists(): fn.unlink() run_cmd( [str(PGM / "exec" / f"hycs_std{exe_suffix}")], "Running hycs_std" )