Source code for bldfm.cli

"""
Command-line interface for BLDFM.

Usage:
    bldfm run config.yaml
    bldfm run config.yaml --dry-run
    bldfm run config.yaml --plot
"""

import argparse
import os
import sys

from . import initialize
from .config_parser import load_config
from .interface import run_bldfm_single
from .utils import get_logger


[docs] def cmd_run(args): """Execute a BLDFM run from a YAML config file.""" initialize() logger = get_logger("cli") config = load_config(args.config) logger.info(f"Loaded config: {args.config}") logger.info( f" Domain: {config.domain.nx}x{config.domain.ny}, nz={config.domain.nz}" ) logger.info(f" Towers: {len(config.towers)}") logger.info(f" Timesteps: {config.met.n_timesteps}") if args.dry_run: logger.info("Dry run complete. Config is valid.") for tower in config.towers: logger.info( f" Tower '{tower.name}': lat={tower.lat}, lon={tower.lon}, " f"z_m={tower.z_m}, x={tower.x:.1f}, y={tower.y:.1f}" ) return # Apply runtime settings from . import config as runtime_config runtime_config.NUM_THREADS = config.parallel.num_threads runtime_config.MAX_WORKERS = config.parallel.max_workers runtime_config.USE_CACHE = config.parallel.use_cache # Run for each tower and timestep results = [] for tower in config.towers: logger.info(f"Running tower '{tower.name}'...") for t in range(config.met.n_timesteps): result = run_bldfm_single(config, tower, met_index=t) results.append(result) logger.info(f" t={result['timestamp']}: done") logger.info("All runs complete.") if args.plot: _save_plots(results, logger)
def _save_plots(results, logger): """Save a footprint PNG for each result.""" import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt from .plotting import plot_footprint_field os.makedirs("plots", exist_ok=True) for result in results: name = result["tower_name"] ts = result["timestamp"] fname = f"plots/footprint_{name}_t{ts}.png" fig, ax = plt.subplots() plot_footprint_field( result["flx"], result["grid"], ax=ax, contour_pcts=[0.5, 0.8], title=f"{name} (t={ts})", ) tx, ty = result["tower_xy"] ax.plot( tx, ty, "k^", markersize=10, markeredgecolor="white", markeredgewidth=1.5, zorder=5, ) fig.savefig(fname, dpi=150, bbox_inches="tight") plt.close(fig) logger.info(f" Saved {fname}")
[docs] def main(): """Main CLI entry point.""" parser = argparse.ArgumentParser( prog="bldfm", description="BLDFM - Boundary Layer Footprint Dispersion Model", ) subparsers = parser.add_subparsers(dest="command") # 'run' subcommand run_parser = subparsers.add_parser("run", help="Run BLDFM from a YAML config file") run_parser.add_argument("config", help="Path to YAML configuration file") run_parser.add_argument( "--dry-run", action="store_true", help="Validate config without running the solver", ) run_parser.add_argument( "--plot", action="store_true", help="Save footprint plots to plots/" ) args = parser.parse_args() if args.command is None: parser.print_help() sys.exit(1) if args.command == "run": cmd_run(args)
if __name__ == "__main__": main()