Skip to content

Run a solver job

Submit a scenario to the Sympheny solver and wait for the optimization to finish. This mirrors clicking Execute in the web application, but scripted end to end.

Prerequisites

Build the request

A solver job is described by a PostSolverJobExt. The request is plain data, so you build it the same way whichever client you use:

from sympheny_toolbox.models import ObjectiveFunction, PostSolverJobExt, TemporalResolution

request = PostSolverJobExt(
    name="Battery evaluation",
    objective1=ObjectiveFunction.min_life_cycle_cost,
    objective2=ObjectiveFunction.min_co2_emissions,
    scenario_guid="your-scenario-guid",
    temporal_resolution=TemporalResolution.low,
    points=2,
    time_limit=30,
    mip_gap=1.0,
)
  • objective1 / objective2 — the optimization objectives (see ObjectiveFunction). With two objectives the solver returns a Pareto front of points solutions.
  • temporal_resolution — how aggressively the 8760-hour year is clustered before solving (LOW/MEDIUM/HIGH/FULL); lower is faster, coarser.
  • mip_gap — the optimality gap, in percent, at which the solver stops.

time_limit is in minutes

time_limit is the solver's processing budget in minutes (queue time excluded), not seconds. The server terminates a job once it is exceeded.

Submit and poll

Submit the request, then poll the job until it reaches a terminal status. DONE means the optimization succeeded; STOPPED, FAILED, and INVALID are terminal failures.

import asyncio

from sympheny_toolbox import AsyncSympheny
from sympheny_toolbox.models import JobStatus

TERMINAL = {JobStatus.done, JobStatus.stopped, JobStatus.failed, JobStatus.invalid}


async def main() -> None:
    async with AsyncSympheny("you@example.com", "password") as client:
        submitted = await client.solver_jobs.submit([request])
        job_id = submitted[0].id

        while True:
            job = await client.solver_jobs.get(job_id)
            print(job.status)
            if job.status in TERMINAL:
                break
            await asyncio.sleep(10)

        if job.status is not JobStatus.done:
            raise RuntimeError(f"Job did not finish cleanly: {job.status}{job.infeasibility_info}")
        print("finished job", job_id)


asyncio.run(main())
import time

from sympheny_toolbox import Sympheny
from sympheny_toolbox.models import JobStatus

TERMINAL = {JobStatus.done, JobStatus.stopped, JobStatus.failed, JobStatus.invalid}

with Sympheny("you@example.com", "password") as client:
    submitted = client.solver_jobs.submit([request])
    job_id = submitted[0].id

    while True:
        job = client.solver_jobs.get(job_id)
        print(job.status)
        if job.status in TERMINAL:
            break
        time.sleep(10)

    if job.status is not JobStatus.done:
        raise RuntimeError(f"Job did not finish cleanly: {job.status}{job.infeasibility_info}")
    print("finished job", job_id)

submit takes a list of requests and returns one SolverJob per request, so you can batch several scenarios in a single call and poll each id.

Shortcut (sync client only)

workflows.execute_scenario builds the request, submits it, and polls to termination in one call, raising if the scenario is infeasible:

from sympheny_toolbox import Sympheny, workflows

with Sympheny("you@example.com", "password") as client:
    job = workflows.execute_scenario(client, "your-scenario-guid", time_limit=30)
    print(job.status)  # JobStatus.done

Use workflows.execute_scenarios to submit many at once. Both are built on the synchronous client; on the async client, use the submit-and-poll loop above.