Stock

BPTK API Documentation for the Stock class
Keywords

system dynamics, bptk, bptk-py, python, business prototyping

Stock

Stock in a SD DSL model.

A stock is what a system remembers. Its value at any instant cannot be read off the rest of the system: it is the accumulation of everything that has flowed in and out since the start, which is why it needs both an initial value and an equation.

Create one through the model rather than directly: model.stock("population").

Stock Constructor

Stock(model, name)

Create the stock.

Stock.equation

property equation

The net change per timestep, not the value — usually the inflows minus the outflows. Read, it returns the equation as originally set - an SD DSL Element or Operator.

population.equation = births - deaths

Writing the equation replaces the flow lists below. A non-negative stock refuses it: its equation comes from its lists.

Stock.inflows

property inflows

The flows into the stock, as a list. Setting it, or outflows, writes the equation as the inflows minus the outflows - the way XMILE describes a stock:

population.inflows = [births, immigration]
population.outflows = [deaths]
# population.equation is now births + immigration - deaths

A list takes flows and biflows. A flow leaves one stock only, so naming a flow among the outflows of a second stock raises ElementError.

Stock.initial_value

property initial_value

The value the stock holds at starttime, before any flow has acted on it. Set it to a number, to a Constant — which is what lets a scenario override it — or to any expression:

population = model.stock("population")
population.initial_value = 80000000.0

# or computed, from constants, converters or a user-defined function
births = model.constant("births")
births.equation = 800000.0
population.initial_value = births * 100

The expression is evaluated once, before the run, with t at the start time. A boolean is refused, and so is anything that is not a number or a model expression; the error names the stock.

A scenario cannot set the stock itself as a constant - that would replace its equation and the stock would not move. It raises ValueError naming the stock; set the constant its initial value refers to instead.

Stock.non_negative

property non_negative

True keeps the stock from falling below zero, as Stella does. The outflows are cut back, not the stock: in each timestep they may take, together, what the stock holds plus what flows in during the step, and the first outflow in the list is served first.

store.inflows = [delivery]          # 3 per day
store.outflows = [sales, scrap]     # want 8 and 9 per day
store.non_negative = True
# With 10 in store and dt = 1: sales gets 8, scrap gets the remaining 5, the store is empty

The flows report what they actually took - scrap reads 5, not 9 - so nothing leaves the stock that it did not hold. An arrayed stock is cut back cell by cell; its outflows have its shape.

Three rules come with it:

  • The stock needs its flow lists. A stock whose equation was written directly raises ElementError when it is made non-negative.
  • An outflow that depends on another outflow of the same stock comes after it in the list. The other way round raises ElementError naming both, when the lists are set or at the start of the run.
  • An inflow that depends on one of the stock’s outflows is not counted towards what the outflows may take; only the stock’s content is.

A biflow is cut back while it drains the stock and left alone while it fills it. Among the outflows it is served at its place in the list; among the inflows it drains the stock when it runs backwards, and is then served after every outflow. Filling, it counts towards what the outflows may take, from either list. A flow is cut back by one stock only.

A non-negative stock runs on the Python engine only for now; backend="rust" raises RustBackendError naming the stock.

Stock.outflows

property outflows

The flows out of the stock, as a list. For a non-negative stock the order is the priority in which they are served.

Inherited from Element

Everything else — equation, function_string, plot() and the arrayed-element API — comes from Element, where it is documented once for all element types.