- states are defined by the types-files
- states are automatically integrated
- states have a unit that ought to be checked in its owner's
preRunChecksby calling the State's
- 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
- this rate is called
<state name>.rateand 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.
|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.): self.doWhenHardy() else: self.doWhenFrostSensitive()
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
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
The same applies to the
reset()-method (which resets rate and state to zero).
what if I must empty a state e.g. during
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. self.state.integrate(0.5) print "new value:", self.state.value def doOnIntegration(self, aState, effective_rate, old_value): print ".. in doOnIntegration" print (aState, effective_rate, old_value) Demo().demonstrateCallBack()
.. in doOnIntegration (<BaseModel.states.AdhocState object at 0x00B17F50>, 50.0, 123.0) new values: 173.0