Experiments#

Experiments: steps that operate a model through its controls, and the runner.

class pytes.experiments.Experiment(operating_conditions)[source]#

Bases: object

A sequence of steps.

Parameters:

operating_conditions (list) – Steps, or tuples (or lists) of steps that form a cycle. As in PyBaMM, a list can be repeated, e.g. [(charge, discharge)] * 5.

Variables:
  • cycles (list of list) – The steps of each cycle (a single step forms a cycle of its own).

  • steps (list) – All the steps, in order.

Raises:

TypeError – If an item is not a pytes.experiments.step step (for example, a PyBaMM step string).

property unique_steps#

One step per model branch, in order of first appearance

pytes.experiments.build_experiment_model(model, experiment, parameter_values)[source]#

Build the experiment version of a model: its controls become solver unknowns, fixed by the active step’s control residuals.

Parameters:
Returns:

model, parameter_values, branch_index, input_names – The new model and parameter values, the branch (1-based) of each step’s branch_key, and the names of all the solver inputs the model needs.

Raises:

ValueError – If a step drives controls the model does not declare.

pytes.experiments.run_experiment(model, experiment, parameter_values=None, var_pts=None, solver=None)[source]#

Run an experiment on a heat battery model.

Parameters:
  • model (pytes.BaseModel) – The model. It is not modified.

  • experiment (Experiment) – The steps to run.

  • parameter_values (pybamm.ParameterValues, optional) – Defaults to the model’s default parameter values. The controls in it are replaced by the steps.

  • var_pts (dict, optional) – Mesh points, as for pybamm.Simulation.

  • solver (pybamm.BaseSolver, optional) – Defaults to the model’s default solver (it must handle algebraic equations).

Returns:

pybamm.Solution – The solution of the whole experiment. solution.cycles holds one solution per cycle, and solution.cycles[i].steps one per step, each with its termination (the duration, or the termination condition that ended it) and its description (step_description()). Steps whose termination condition already holds when they start are skipped, with a warning. If the solver fails during a step, the experiment stops there with a warning, and the solution up to the end of the previous step is returned (as for PyBaMM experiments).

pytes.experiments.step_description(step_solution)[source]#

The description of the step a step solution belongs to.

Parameters:

step_solution (pybamm.Solution) – One of solution.cycles[i].steps.

Returns:

str or None

Steps#

Steps of a heat battery experiment, run with pytes.experiments.run_experiment().

A model declares its controls (DESIGN D9); today they are the inlet temperature and the mass flow rate. Each step declares the controls it drives. In an experiment the controls are solver unknowns, and each step fixes them with one equation each (its control residuals): either by holding them at given values, or by adjusting one of them to hold the power. This follows the “unified” experiment mode of PyBaMM, so that the steps can move to PyBaMM’s own experiment framework once it supports models other than batteries.

The values a step holds can be constants, measured time series (a 2-column array of time since the start of the step [s] and value) or functions of the time since the start of the step [s]. Constant values are passed to the solver as inputs, so steps that only differ in their constant values share the same compiled model branch.

The steps are named after what they hold, as PyBaMM’s (pybamm.step.Current, Power, Rest): Inlet holds the inlet conditions, Power the power and Rest no flow. The power is positive when the battery delivers heat (discharge), so a charge uses a negative power.

pytes.experiments.step.START_TIME = InputParameter(-0x5c83055ada892b93, Step start time [s], children=[], domains={})#

Input parameter holding the time [s] at which the current step started

pytes.experiments.step.DEFAULT_DURATION = 86400#

Default step duration [s] when neither a duration nor a time series sets it

pytes.experiments.step.DEFAULT_PERIOD = 60#

Default time between output points [s]

pytes.experiments.step.PREVIOUS_INLET_TEMPERATURE = InputParameter(-0x5137806a96bba32f, Inlet temperature at the end of the previous step [K], children=[], domains={})#

Input parameter holding the inlet temperature [K] at the end of the previous step, which a Rest holds by default

class pytes.experiments.step.Termination(name, function)[source]#

Bases: object

A condition that ends a step, used in addition to its duration.

Parameters:
  • name (str) – Name of the condition, used to report why a step ended.

  • function (callable) – Function of the model variables (a dict of symbols) returning an expression that is positive while the step should continue, and crosses zero when it should end.

expression(variables)[source]#

The condition as an expression.

Parameters:

variables (dict) – Model variables.

Returns:

pybamm.Symbol – Positive while the step should continue; the step ends when it crosses zero.

property key#

Identity of the condition, used to decide which steps share a model branch

pytes.experiments.step.outlet_temperature_below(T)[source]#

End the step when the outlet temperature [K] falls below T

pytes.experiments.step.outlet_temperature_above(T)[source]#

End the step when the outlet temperature [K] rises above T

pytes.experiments.step.inlet_temperature_below(T)[source]#

End the step when the inlet temperature [K] falls below T

pytes.experiments.step.inlet_temperature_above(T)[source]#

End the step when the inlet temperature [K] rises above T

pytes.experiments.step.mass_flow_rate_above(mdot)[source]#

End the step when the mass flow rate [kg.s-1] rises above mdot

pytes.experiments.step.average_liquid_fraction_below(phi)[source]#

End the step when the average liquid fraction falls below phi

pytes.experiments.step.average_liquid_fraction_above(phi)[source]#

End the step when the average liquid fraction rises above phi

class pytes.experiments.step.Target(name, value)[source]#

Bases: object

A value held by a step: a constant, a 2-column time series (time since the start of the step [s], value) or a function of the time since the start of the step [s].

A time series is interpolated linearly, and its last value is held if the step lasts longer than the series (unlike PyBaMM drive cycles, which are repeated).

Parameters:
  • name (str) – Name of the quantity, e.g. “Inlet temperature [K]”.

  • value (float, numpy.ndarray or callable) – A constant, a 2-column array of time since the start of the step [s] (starting at 0) and value, or a function of the time since the start of the step [s] (a pybamm.Symbol) returning a symbol.

Raises:
  • ValueError – If a time series is not a 2-column array starting at time 0.

  • TypeError – If the value is none of the above.

property input_name#

Name of the input parameter holding a constant value

symbol()[source]#

The value as a symbol in the model

property key#

Identity, used to decide which steps share a model branch

property initial_value#

Value at the start of the step, as a number

property end_time#

Last time of a time series, or None

class pytes.experiments.step.BaseStep(targets, duration=None, termination=None, period=None, description=None)[source]#

Bases: object

Base class for experiment steps.

Subclasses declare the controls they drive (controls), pass their targets to this constructor and implement control_residuals().

Parameters:
  • targets (list of Target) – The values the step holds.

  • duration (float, optional) – Maximum duration of the step [s]. Defaults to the length of the step’s time series if it has one, otherwise one day.

  • termination (Termination or list of them, optional) – Conditions that end the step before its duration.

  • period (float, optional) – Time between output points [s] (default 60 s).

  • description (str, optional) – Description of the step, used when reporting results.

controls = ('Inlet temperature [K]', 'Mass flow rate [kg.s-1]')#

Names of the controls the step drives

safety_terminations()[source]#

Terminations every step of this type needs (none by default)

control_residuals(variables, targets, power)[source]#

Equations fixing the controls.

Parameters:
  • variables (dict) – Model variables, including the controls and “Power [W]”.

  • targets (dict) – The step’s target values as symbols, keyed by name.

  • power (callable) – The model’s power [W] with some controls replaced: power(controls), with controls a dict of symbols keyed by control name (see pytes.BaseModel.power()).

Returns:

dict – One residual per control in controls, keyed by control name.

termination_expression(variables)[source]#

Combined termination: positive while the step should continue

property branch_key#

the same type, the same kind of targets (constant inputs, or the same time series) and the same terminations.

Type:

Steps with the same key share a model branch

input_values()[source]#

Values of the constant targets, as solver inputs

class pytes.experiments.step.Inlet(inlet_temperature, mass_flow_rate, **kwargs)[source]#

Bases: BaseStep

Hold the inlet conditions: the inlet temperature [K] and the mass flow rate [kg.s-1]. Each can be a constant, a time series or a function of time (see Target).

Parameters:
  • inlet_temperature (float, numpy.ndarray or callable) – Inlet temperature [K].

  • mass_flow_rate (float, numpy.ndarray or callable) – Mass flow rate through the whole device [kg.s-1]. For no flow, use Rest.

  • **kwargs – duration, termination, period and description, see BaseStep.

control_residuals(variables, targets, power)[source]#

Both controls equal their targets

class pytes.experiments.step.Rest(inlet_temperature=None, **kwargs)[source]#

Bases: BaseStep

Stop the flow: hold the mass flow rate at 0. The inlet temperature has no effect without flow, but the model still needs a value: by default the step holds it where the previous step left it (the initial temperature for a first step), so that the inlet temperature does not jump.

Parameters:
  • inlet_temperature (float, numpy.ndarray or callable, optional) – Inlet temperature [K] to hold instead (see Target).

  • **kwargs – duration, termination, period and description, see BaseStep.

property holds_previous_inlet_temperature#

Whether the step holds the inlet temperature of the previous step

control_residuals(variables, targets, power)[source]#

No flow, and the inlet temperature at its target or its previous value

class pytes.experiments.step.Power(power, *, inlet_temperature=None, mass_flow_rate=None, **kwargs)[source]#

Bases: BaseStep

Hold the power [W] (positive for discharge) by adjusting the one control that is not given (DESIGN D10). Give exactly one of:

  • mass_flow_rate: the inlet temperature is adjusted. Use inlet_temperature_below() and inlet_temperature_above() to limit it.

  • inlet_temperature: the mass flow rate is adjusted. Use mass_flow_rate_above() to limit it: the flow needed grows without bound as the outlet temperature approaches the inlet temperature. The step also ends if the mass flow rate would become negative.

Parameters:
  • power (float, numpy.ndarray or callable) – Power of the whole battery [W], positive for discharge and negative for charge.

  • inlet_temperature (float, numpy.ndarray or callable, optional) – Inlet temperature [K], held.

  • mass_flow_rate (float, numpy.ndarray or callable, optional) – Mass flow rate through the whole device [kg.s-1], held. Must not be 0: no power can be exchanged without flow.

  • **kwargs – duration, termination, period and description, see BaseStep.

Variables:

adjusted (str) – Name of the control the step adjusts.

Raises:

ValueError – If both controls or neither are given.

safety_terminations()[source]#

End the step if the mass flow rate, when adjusted, would become negative

control_residuals(variables, targets, power)[source]#

The held control equals its target, and the power, written with the held control at its target, equals its target