Generators¶
Generate Code¶
The Dymodetron code generator creates code to simulate a model. The code generator takes a model definition file as input, and creates an output file containing the simulation code.
The code generator is a python module that can be invoked from the command line, as follows.
Use --help
to list the command line arguments.
# python generated/python_arrayified/cat_model.py --help
usage: cat_model.py [-h] [--num_entities NUM_ENTITIES] [--enable_logging ENABLE_LOGGING] [--rand_seed RAND_SEED] [--end_time_ticks END_TIME_TICKS] [--progress_interval_ticks PROGRESS_INTERVAL_TICKS]
optional arguments:
-h, --help show this help message and exit
--num_entities NUM_ENTITIES
Number of entity instances.
--enable_logging ENABLE_LOGGING
Enable logging, or not.
--rand_seed RAND_SEED
Random number seed.
--end_time_ticks END_TIME_TICKS
Simulation end time (ticks).
--progress_interval_ticks PROGRESS_INTERVAL_TICKS
Interval between reporting sim progress (ticks).
For example, you can generate the code for the example cat model by running the following from the root Dymodetron directory.
# python -m dymodetron.generators.python_arrayified --model_definition_file=examples/cat.py --overwrite_existing=1
python_arrayified
Generating code for entity type [Cat]
Outputting to [generated/python_arrayified/cat_model.py]
Run Code¶
After you’ve generated the simulation code, you can run it as follows.
# python generated/python_arrayified/cat_model.py --enable_logging=1 --end_time_ticks=100 --progress_interval_ticks=10
Which will result in output something like the following. First it reads back the arguments, some of which have default values because they weren’t specified on the command line.
Then, time progress log messages are displayed. The formatting has to do with the logger configuration.
Finally, the State Tracking
report is displayed. In this case, our model only has state tracking
enabled for the ‘eating’ state, so that is the only one that shows any results: track_cumulative=400
.
This says that the state ‘eating’ was entered 400 times by a cat. Some of these are
repeat occurrences of the same cat entering the ‘eating’ state multiple times.
(The state ‘eating’ exists in sub-state-machine ‘awake’, in state machine ‘cat_sleeping_eating_drinking’.)
The track_cumulative=None
indicators tell you about states where state tracking is not enabled.
Read about enabling state tracking here.
# python generated/python_arrayified/cat_model.py --enable_logging=1 --end_time_ticks=100 --progress_interval_ticks=10
Sim Arguments:
{
'enable_logging': 1,
'end_time_ticks': 100.0,
'num_entities': 100,
'progress_interval_ticks': 10.0,
'rand_seed': 1,
}
INFO:__main__:t = 0.0
INFO:__main__:t = 10.0
INFO:__main__:t = 20.0
INFO:__main__:t = 35.0
INFO:__main__:t = 45.0
INFO:__main__:t = 60.0
INFO:__main__:t = 70.0
INFO:__main__:t = 85.0
INFO:__main__:t = 95.0
-----------------------------------
State Tracking
-----------------------------------
instance(Entities_Cat_state_tracking):
cat_sleeping_eating_drinking__awake: StateTracking(track_cumulative=None),
cat_sleeping_eating_drinking__awake__drinking: StateTracking(track_cumulative=None),
cat_sleeping_eating_drinking__awake__eating: StateTracking(track_cumulative=400),
cat_sleeping_eating_drinking__awake__staring_out_window: StateTracking(track_cumulative=None),
cat_sleeping_eating_drinking__sleeping: StateTracking(track_cumulative=None)
Note
The progress_interval_ticks
argument throttles the printing of the message t = xyz
indicating
simulation progress.
You’ll notice that the printed event times don’t come on even multiples of 10. This is because for this simulation,
there aren’t necessarily events occurring at every t = n * 10
. The progress_interval_ticks
sets an upper
limit on how many messages you’ll see every n
ticks, but doesn’t make them show up on regular intervals.
You can get display additional information about event scheduling and processing by setting
environment variable LOGLEVEL=DEBUG
:
# LOGLEVEL=DEBUG python generated/python_arrayified/cat_model.py --enable_logging=1 --end_time_ticks=30 --progress_interval_ticks=10
Which provides the additional output shown below:
# LOGLEVEL=DEBUG python generated/python_arrayified/cat_model.py --enable_logging=1 --end_time_ticks=30 --progress_interval_ticks=10
Sim Arguments:
{
'enable_logging': 1,
'end_time_ticks': 30.0,
'num_entities': 100,
'progress_interval_ticks': 10.0,
'rand_seed': 1,
}
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=0.0, event_id=0, event_obj=<__main__.initial_event_types.initial_event_cat_sleeping_eating_drinking object at 0x7fb4370b4e20>, entity_ids=None)]
INFO:__main__:t = 0.0
DEBUG:__main__:Processing event: [ScheduledEvent(time_ticks=0.0, event_id=0, event_obj=<__main__.initial_event_types.initial_event_cat_sleeping_eating_drinking object at 0x7fb4370b4e20>, entity_ids=None)]
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=10.0, event_id=1, event_obj=<examples.cat.not_tired_event object at 0x7fb4370c5a30>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
INFO:__main__:t = 10.0
DEBUG:__main__:Processing event: [ScheduledEvent(time_ticks=10.0, event_id=1, event_obj=<examples.cat.not_tired_event object at 0x7fb4370c5a30>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=10.0, event_id=2, event_obj=<__main__.initial_event_types.initial_event_cat_sleeping_eating_drinking__awake object at 0x7fb4370b4970>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Processing event: [ScheduledEvent(time_ticks=10.0, event_id=2, event_obj=<__main__.initial_event_types.initial_event_cat_sleeping_eating_drinking__awake object at 0x7fb4370b4970>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Event was scheduled with no target entity_ids: [<examples.cat.hungry_event object at 0x7fb4370c5b20> @ 15.0]
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=17.0, event_id=3, event_obj=<examples.cat.thirsty_event object at 0x7fb4370c5be0>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Processing event: [ScheduledEvent(time_ticks=17.0, event_id=3, event_obj=<examples.cat.thirsty_event object at 0x7fb4370c5be0>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=20.0, event_id=4, event_obj=<examples.cat.not_thirsty_event object at 0x7fb4370b4e50>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
INFO:__main__:t = 20.0
DEBUG:__main__:Processing event: [ScheduledEvent(time_ticks=20.0, event_id=4, event_obj=<examples.cat.not_thirsty_event object at 0x7fb4370b4e50>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=25.0, event_id=5, event_obj=<examples.cat.hungry_event object at 0x7fb4370c5a90>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Event was scheduled with no target entity_ids: [<examples.cat.thirsty_event object at 0x7fb4370c5d30> @ 27.0]
DEBUG:__main__:Processing event: [ScheduledEvent(time_ticks=25.0, event_id=5, event_obj=<examples.cat.hungry_event object at 0x7fb4370c5a90>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
DEBUG:__main__:Scheduling event: [ScheduledEvent(time_ticks=35.0, event_id=6, event_obj=<examples.cat.not_hungry_event object at 0x7fb4370b4e50>, entity_ids=array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]))]
-----------------------------------
State Tracking
-----------------------------------
instance(Entities_Cat_state_tracking):
cat_sleeping_eating_drinking__awake: StateTracking(track_cumulative=None),
cat_sleeping_eating_drinking__awake__drinking: StateTracking(track_cumulative=None),
cat_sleeping_eating_drinking__awake__eating: StateTracking(track_cumulative=100),
cat_sleeping_eating_drinking__awake__staring_out_window: StateTracking(track_cumulative=None),
cat_sleeping_eating_drinking__sleeping: StateTracking(track_cumulative=None)
Generate Diagrams¶
The Dymodetron diagram generator creates state machine diagrams for each state machine in your model.
The diagram generator is a python module that can be invoked from the command line, as follows.
Use --help
to list the command line arguments.
# python -m dymodetron.generators.state_machine_diagrams --help
usage: state_machine_diagrams.py [-h] --model_definition_file MODEL_DEFINITION_FILE [--output_folder OUTPUT_FOLDER] [--overwrite_existing OVERWRITE_EXISTING]
optional arguments:
-h, --help show this help message and exit
--model_definition_file MODEL_DEFINITION_FILE
Location of model definition file.
--output_folder OUTPUT_FOLDER
Output folder in which to place the generated diagrams.
--overwrite_existing OVERWRITE_EXISTING
Whether or not to overwrite existing diagrams in the output folder, if they already exist.
For example, you can generate the diagrams for the example cat model by running the following from the root Dymodetron directory.
# python -m dymodetron.generators.state_machine_diagrams --model_definition_file=examples/cat.py --overwrite_existing=1
state_machine_diagrams
Generating state machine diagram for state machine [cat_sleeping_eating_drinking]
Outputting to [generated/state_machine_diagrams/cat_sleeping_eating_drinking.html]
Each state machine in your model will output to its own diagram file. This model has one state machine model, so there’s one diagram file.
The state chart diagram is an html file. Load it into your web browser to view it. It should look like the following.