Analysis

Operating limits

class ionworkspipeline.analysis.OperatingLimit(protocol: str, parameter: Parameter, objective: BaseAction, constraints: dict[str, BaseAction], tolerance: float = 0.0001, name: str | None = None)

The best value of one protocol input for which the protocol meets its limits.

protocol defines the whole experiment (preconditioning, then the pulse or mission) and reads the searched value as input["<parameter name>"]. The search minimizes objective subject to constraints with Bisection, so the optimum must sit on the feasibility boundary: the objective improves toward it, and feasibility changes once between the bounds. solve() returns the protocol’s UCP solution at the limit, with the limit stored in its metrics; find() returns the limit alone.

Parameters

protocolstr

UCP protocol YAML containing input["<parameter name>"].

parameteriwp.Parameter

The searched input, with bounds. It cannot be transformed (e.g. Log10): a transformed parameter reaches the simulation under its transformed name, which no protocol input reads.

objectiveBaseAction

What the limit optimizes, e.g. Maximize(Last("Time [s]")) for the longest mission. It decides which side of the boundary is the limit when both bounds meet the constraints.

constraintsdict[str, BaseAction]

Conditions the run must meet, e.g. {"Voltage floor": GreaterThan(Minimum("Voltage [V]"), 3.0)}; slice a metric with .by_step(...) to judge only part of the protocol. A run the solver cannot complete counts as violating them.

tolerancefloat, optional

Bracket width at which the search stops, as a fraction of the bounds’ width. Default 1e-4.

namestr, optional

Key of the limit in the solution’s metrics. Defaults to the parameter’s name.

Examples

>>> limit = iwp.analysis.OperatingLimit(
...     protocol=mission_yaml,  # cruise step: duration: input["Cruise time [s]"]
...     parameter=iwp.Parameter("Cruise time [s]", bounds=(1, 7200)),
...     objective=Maximize(Last("Time [s]")),
...     constraints={"Voltage floor": GreaterThan(Minimum("Voltage [V]"), 3.0)},
... )
>>> solution = limit.solve(model, parameter_values)
>>> solution.metrics["Cruise time [s]"]
class ionworkspipeline.analysis.PeakPower(protocol: str, voltage_limit: float | None = None, direction: Literal['Discharge', 'Charge'] = 'Discharge', bounds: tuple[float, float] | None = None, tolerance: float = 1e-05)

The highest constant power a protocol’s pulse holds for its full duration.

The voltage limit is armed as a safety limit of the protocol, so a pulse the cell cannot hold ends the run early. The peak power is the highest input["Power [W]"] for which the run reaches the end time it reaches at the lowest power searched. Every step that reads the input runs at that power, so a protocol may read it in more than one step.

Parameters

protocolstr

UCP protocol YAML whose pulse step is mode: Power with value: input["Power [W]"]; earlier steps set the state the pulse starts from.

voltage_limitfloat, optional

Voltage at which the run ends [V], replacing the protocol’s own safety limit on that side. Defaults to that limit’s value (and delay), or, when the protocol sets none, to the parameter set’s lower voltage cut-off for discharge and upper cut-off for charge. The limit always ends the run: a goto the protocol gives it is not followed while searching.

direction{“Discharge”, “Charge”}, optional

Whether the pulse discharges (default) or charges the cell, which sets the side of the voltage limit and the name of the result.

boundstuple[float, float], optional

Power range searched [W]. Defaults to 1/100 to 100 times the cell’s 1C power at its upper cut-off voltage.

tolerancefloat, optional

See OperatingLimit. Default 1e-5, i.e. 0.1% of the cell’s 1C power over the default bounds.

Examples

>>> peak = iwp.analysis.PeakPower(
...     '''
... global: {initial_state_type: soc_percentage, initial_state_value: 50}
... steps:
...   - Discharge: {mode: Power, value: 'input["Power [W]"]', duration: 10}
... '''
... )
>>> peak.solve(model, parameter_values).metrics["Peak power [W]"]
search_protocol(parameter_values, subroutines=None)

The protocol with the voltage limit armed as its safety limit.

Parameters

parameter_valuespybamm.ParameterValues

The cell’s parameter values, whose cut-off is the default limit.

subroutinesdict, optional

The protocol’s subroutines, as given to find(); the block the limit jumps to takes a name none of them uses.

Returns

dict or Protocol

The protocol, ending the run when the voltage limit fires, even where the protocol’s own limit, or its global goto, jumps elsewhere.