Using states

Jump to: navigation, search
  • states are defined by the types-files
  • states are automatically integrated
  • states have a unit that ought to be checked in its owner's preRunChecks by calling the State's checkUnits-method
  • the current value of a state is available as a property (read-only) of its owner; the name of the property is exactly the state name (case sensitive!)
  • the rate used by the integration to modify the state must be defined in calculateRates
  • this rate is called <state name>.rate and is available as a property (read/write) of its owner; however, directly setting the rate normally is not a good practice since it breaks the mass balance (if any) and could overwrite rate-changes in other parts of the code.

defining states

in the type file
<state name="hardiness" units="K">249.85</state>

this can be placed anywhere within the component.

on the fly
def initializeAtT0(self):
    super(Phenology, self).initializeAtT0()
    self.addState("hardiness", 249.85)

getting the state's value

The state becomes a (read-only) attribute of the component and can be used as if it were a floating point value:

if (self.hardiness > 250.):

The state can be used in calculations:

rate = rgr * self.Carbon

Mind, however, that the state is not a float. To get the current float value, use float():

s = self.Carbon
c = s.float()
print "value:", c
print "state:", s
print "calc.:", s * 1

value: 123.456
state: Carbon: 123.456000 m.s-1 (dx/dt = 0.000000)
calc.: 123.456

changing the state's value

The value of a State is encapsulated, that is, not normally accessible. To read the current value, the float()-metod is available. Setting the value is not encouraged, however, inevitable in incidental cases. The value can be set with the setValue()-method. Since doing so could interfere with the integration process, this method is locked during integration. Within the dynamic loop of the model run, setValue() may be used during startOfNextIntegrationCycle() and afterIntegration().

The same applies to the reset()-method (which resets rate and state to zero).

what if I must empty a state e.g. during calculateRates()..?

If you really have to, then call not just reset(), but use an extra argument:


safely transfering between states

Often, when specifying material flow the influx into one state is outflow from another state, so what's credited to state A inherently must be debited to state B.

# transfer abolute amount from A to B:
self.A.transferTo(B, 123.4546)
# transfer 12.3% of A to B(fraction):
self.A.transferFractionTo(B, 0.123)

how to get the effective rate

The calculation of the rates is the main business of the model, but the rates are calculated as momentanous transfer speeds. The effective rate, i.e. the amount added to or deducted from a state, is known only during integration, taking into account timestep and integration method.

Normally, there's no need to know the effective rates.

However, when mixing models of diiferent nature, the exact amounts transfered may be required. This can be achieved by assigning a call-back method to the state. Every state has the attribute OnIntegration, which may be connected to a procedure with the signature

 (aState, effective_rate, old_value)

Both bound and unbound functions are allowed.

class Demo():
  def __init__(self):
    self.state = AdhocState('demoState', 123.)
    self.state.onIntegration = self.doOnIntegration
  def demonstrateCallBack(self):
    self.state.rate = 100.
    print "new value:", self.state.value
  def doOnIntegration(self, aState, effective_rate, old_value):
    print ".. in doOnIntegration"
    print (aState, effective_rate, old_value)

.. in doOnIntegration
(<BaseModel.states.AdhocState object at 0x00B17F50>, 50.0, 123.0)
new values: 173.0

see also

defining states in the type-file