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.

%%{init: { 'theme': 'base' } }%% stateDiagram-v2 awake sleeping [*] --> sleeping : initial_event sleeping --> awake : not_tired_event awake --> sleeping : tired_event state awake { drinking eating staring_out_window [*] --> staring_out_window : initial_event staring_out_window --> eating : hungry_event eating --> staring_out_window : not_hungry_event staring_out_window --> drinking : thirsty_event drinking --> staring_out_window : not_thirsty_event }