Skip to content

RasControl.run_plan reports success when the result HDF does not exist #323

Description

@jacobrbeatty

RasControl.run_plan trusts HEC-RAS's COM PlanOutput_IsCurrent() and returns success without checking that a result file exists. On a plan that has never been computed, PlanOutput_IsCurrent() returned True, so run_plan returned success=True in 1.9 s with no result HDF on disk at all.

Reproduction

HEC-RAS 7.0 (April 2026), ras-commander 0.98.2, Windows 11, Python 3.14.

from ras_commander import RasPrj, RasControl, init_ras_project

prj = RasPrj()
init_ras_project(r"...\Montevallo.prj", "7.0", ras_object=prj)

result = RasControl.run_plan("13", ras_object=prj)   # plan 13 never computed
print(result.success)    # True
print(result.messages)   # ['Results are current - computation skipped']
INFO  Plan 13 results are current. Skipping computation.
INFO  Use force_recompute=True to recompute anyway.
RESULT: success=True in 1.9 s
result HDF exists: False

Montevallo.p13.hdf did not exist before or after the call.

Cause

RasControl.py, in run_plan -> _run_operation:

if not force_recompute:
    try:
        is_current = com_rc.PlanOutput_IsCurrent()
        if is_current:
            logger.info(f"Plan {info.plan_number} results are current. Skipping computation.")
            logger.info("Use force_recompute=True to recompute anyway.")
            return True, ["Results are current - computation skipped"]

The staleness answer comes from HEC-RAS, and "current" is taken to imply "present". Absence reads as up to date.

Why it matters beyond one call

Any batch that spawns a fresh model copy per run starts with no result HDF, so this can green-light a whole campaign that produced nothing — a model copy per mainstem in a ras2fim-style sweep, or an unattended SLURM run.

RasCmdr is not affected. compute_plan(..., verify=True) calls _verify_completion, which handles this correctly — I tested it against four real failed runs and three good ones and it was right 7 for 7, including passing a legitimate steady result that has Results/Steady and no Results/Unsteady. The fix below just brings RasControl up to that.

Suggested fix

Reuse the existing verifier rather than adding a second definition of "done":

if not force_recompute:
    try:
        is_current = com_rc.PlanOutput_IsCurrent()
        if is_current:
            hdf_path = RasCmdr._get_hdf_path(info.plan_number, ras_obj)
            if hdf_path is None or not RasCmdr._verify_completion(Path(hdf_path)):
                logger.info(
                    "PlanOutput_IsCurrent() reported current but no valid result "
                    "HDF is present; computing."
                )
            else:
                logger.info(f"Plan {info.plan_number} results are current. Skipping computation.")
                return True, ["Results are current - computation skipped"]

Happy to open a PR if the shape looks right — I didn't want to guess whether RasControl should import from RasCmdr or whether the check belongs in a shared helper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions