Tutorial 13 - Python State Node
This node illustrates how you can use internal state information, so long as you inform OmniGraph that you are doing so in order for it to make more intelligent execution scheduling decisions.
OgnTutorialStatePy.ogn
The .ogn file containing the implementation of a node named “omni.graph.tutorials.StatePy”, with an empty state set to inform OmniGraph of its intention to compute using internal state information.
1{
2 "StatePy" : {
3 "version": 1,
4 "categories": "tutorials",
5 "description": [
6 "This is a tutorial node. It makes use of internal state information",
7 "to continuously increment an output."
8 ],
9 "language": "python",
10 "metadata":
11 {
12 "uiName": "Tutorial Python Node: Internal States"
13 },
14 "state": {
15 "$comment": "The existence of this state section, even if it contains no attributes, means there is internal state that is entirely managed by the node"
16 },
17 "inputs": {
18 "overrideValue": {
19 "type": "int64",
20 "description": "Value to use instead of the monotonically increasing internal one when 'override' is true",
21 "default": 0
22 },
23 "override": {
24 "type": "bool",
25 "description": "When true get the output from the overrideValue, otherwise use the internal value",
26 "default": false
27 }
28 },
29 "outputs": {
30 "monotonic": {
31 "type": "int64",
32 "description": "Monotonically increasing output, set by internal state information",
33 "default": 0
34 }
35 },
36 "tests": [
37 { "inputs:overrideValue": 5, "inputs:override": true, "outputs:monotonic": 5 }
38 ]
39 }
40}
OgnTutorialStatePy.py
The .py file contains the compute method and the internal state information used to run the algorithm.
By overriding the special method internal_state
you can define an object that will contain per-node and per-graph-instance
data, that you can manage yourself. It will not be visible to OmniGraph. That data can be accessed with the db passed in
to the compute function, through the per_instance_state
property.
1"""
2Implementation of a Python node that uses internal state information to compute outputs.
3
4There are two types of state information in use here:
5 - OgnTutorialStatePy.step (per-class state information)
6 This is inherently dangerous in a multi-threaded multi-hardware evaluation so
7 it must be used with care. In this case the value is only used when a node is created, which for now is a safe
8 single-threaded operation
9
10 - per-node state information.
11"""
12
13
14class OgnTutorialStatePyInternalState:
15 """Convenience class for maintaining per-node state information"""
16
17 def __init__(self):
18 """Instantiate the per-node state information.
19
20 Note: For convenience, per-node state data is maintained as members of this class, imposing the minor
21 restriction of having no parameters allowed in this constructor.
22
23 The presence of the "state" section in the .ogn node has flagged to omnigraph the fact that this node will
24 be managing some per-node state data.
25 """
26 # Start all nodes with a monotonic increment value of 0
27 self.increment_value = 0
28 # Get this node's internal step value from the per-class state information
29 self.node_step = OgnTutorialStatePy.step
30 # Update the per-class state information for the next node
31 OgnTutorialStatePy.step += 1
32
33 def update_state(self):
34 """Helper function to update the node's internal state based on the previous values and the per-class state"""
35 self.increment_value += self.node_step
36
37
38class OgnTutorialStatePy:
39 """Use internal node state information in addition to inputs"""
40
41 # This is a simplified bit of internal per-class state information. In real applications this would be a complex
42 # structure, potentially keyed off of combinations of inputs or real time information.
43 #
44 # This value increases for each node and indicates the value at which a node's own internal state value increments.
45 # e.g. the first instance of this node type will increment its state value by 1, the second instance of it by 2,
46 # and so on...
47 step = 1
48
49 # Defining this method, in conjunction with adding the "state" section in the .ogn file, tells OmniGraph that you
50 # intend to maintain opaque internal state information on your node. OmniGraph will ensure that your node is not
51 # scheduled for evaluation in such a way that it would compromise the thread-safety of your node due to this state
52 # information, however you are responsible for updating the values and/or maintaining your own dirty bits when
53 # required.
54 @staticmethod
55 def internal_state():
56 """Returns an object that will contain per-node state information"""
57 return OgnTutorialStatePyInternalState()
58
59 @staticmethod
60 def compute(db) -> bool:
61 """Compute the output based on inputs and internal state"""
62
63 # This illustrates how internal state and inputs can be used in conjunction. The inputs can be used
64 # to divert to a different computation path.
65 if db.inputs.override:
66 db.outputs.monotonic = db.inputs.overrideValue
67 else:
68 # OmniGraph ensures that the database contains the correct internal state information for the node
69 # being evaluated. Beyond that it has no knowledge of the data within that state.
70 db.outputs.monotonic = db.per_instance_state.increment_value
71
72 # Update the node's internal state data for the next evaluation.
73 db.per_instance_state.update_state()
74
75 return True