pyjevsim 2.0.0__tar.gz → 2.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyjevsim-2.0.0/pyjevsim.egg-info → pyjevsim-2.0.1}/PKG-INFO +112 -31
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/README.md +111 -30
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/behavior_model.py +1 -1
- pyjevsim-2.0.1/pyjevsim/structural_model.py +133 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/system_executor.py +27 -2
- {pyjevsim-2.0.0 → pyjevsim-2.0.1/pyjevsim.egg-info}/PKG-INFO +112 -31
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyproject.toml +1 -1
- pyjevsim-2.0.0/pyjevsim/structural_model.py +0 -48
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/LICENSE +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/MANIFEST.in +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/__init__.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/atomic_model.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/behavior_executor.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/core_model.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/default_message_catcher.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/definition.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/executor.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/executor_factory.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/exgen.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/message_deliverer.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/restore_handler.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/schedule_queue.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/snapshot_condition.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/snapshot_executor.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/snapshot_factory.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/snapshot_manager.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/structural_executor.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/system_message.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/system_object.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim/termination_manager.py +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim.egg-info/SOURCES.txt +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim.egg-info/dependency_links.txt +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim.egg-info/requires.txt +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/pyjevsim.egg-info/top_level.txt +0 -0
- {pyjevsim-2.0.0 → pyjevsim-2.0.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyjevsim
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: A DEVS(Discrete Event System Specification) Modeling & Simulation environment with journaling functionality
|
|
5
5
|
Author-email: Changbeom Choi <me@cbchoi.info>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,48 +26,129 @@ Requires-Dist: pytest>=7.0; extra == "dev"
|
|
|
26
26
|
Dynamic: license-file
|
|
27
27
|
|
|
28
28
|
# pyjevsim
|
|
29
|
+
|
|
30
|
+
[](https://pypi.org/project/pyjevsim/)
|
|
31
|
+
[](https://pypi.org/project/pyjevsim/)
|
|
32
|
+
[](https://pyjevsim.readthedocs.io/en/latest/)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+
|
|
29
35
|
## Introduction
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
pyjevsim is a DEVS (discrete event system specification) modeling and
|
|
38
|
+
simulation environment with built-in journaling. It supports snapshot
|
|
39
|
+
and restore of individual models or the full simulation engine,
|
|
40
|
+
virtual-time and real-time execution, and HLA federate integration via
|
|
41
|
+
a stepped execution mode. Compatible with Python 3.10+.
|
|
42
|
+
|
|
43
|
+
Full documentation: <https://pyjevsim.readthedocs.io/en/latest/>
|
|
44
|
+
|
|
45
|
+
### What's new in 2.0
|
|
46
|
+
|
|
47
|
+
- **Two-phase tick.** `SysExecutor` evaluates every imminent model's
|
|
48
|
+
`output()` first, then routes outputs and applies transitions —
|
|
49
|
+
fixing confluent-event ordering under Parallel-DEVS semantics.
|
|
50
|
+
- **HLA stepped execution.** `step(granted_time)` and
|
|
51
|
+
`get_next_event_time()` let an IEEE 1516-2010 RTI federate drive
|
|
52
|
+
pyjevsim without owning the main loop.
|
|
53
|
+
- **V_TIME jump-to-next-event.** The virtual-time scheduler hops
|
|
54
|
+
directly to the next scheduled event instead of advancing by a fixed
|
|
55
|
+
`time_resolution`, eliminating idle ticks on sparse models.
|
|
56
|
+
- **Opt-in uncaught-message tracking** for debugging dangling outputs.
|
|
57
|
+
- **DEVStone benchmark suite** with cross-engine comparison adapters.
|
|
58
|
+
|
|
36
59
|
## Installing
|
|
37
|
-
|
|
60
|
+
|
|
61
|
+
From PyPI (recommended):
|
|
62
|
+
|
|
38
63
|
```
|
|
39
|
-
|
|
64
|
+
pip install pyjevsim
|
|
40
65
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
dill is an essential library for serializing models and simulation states and can be installed via.
|
|
66
|
+
|
|
67
|
+
From source:
|
|
68
|
+
|
|
45
69
|
```
|
|
46
|
-
|
|
70
|
+
git clone https://github.com/eventsim/pyjevsim
|
|
71
|
+
cd pyjevsim
|
|
72
|
+
pip install -e .
|
|
47
73
|
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
|
|
75
|
+
## Dependencies
|
|
76
|
+
|
|
77
|
+
- Python >= 3.10
|
|
78
|
+
- `dill >= 0.3.6` (installed automatically) — used for model
|
|
79
|
+
serialization and restoration.
|
|
80
|
+
|
|
81
|
+
`pytest` is required only to run the test suite and is declared under
|
|
82
|
+
the `dev` extra:
|
|
83
|
+
|
|
52
84
|
```
|
|
53
|
-
pip install
|
|
85
|
+
pip install pyjevsim[dev]
|
|
54
86
|
```
|
|
55
|
-
|
|
56
|
-
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
A minimal generator → sink simulation:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pyjevsim.behavior_model import BehaviorModel
|
|
94
|
+
from pyjevsim.definition import ExecutionType, Infinite
|
|
95
|
+
from pyjevsim.system_executor import SysExecutor
|
|
96
|
+
from pyjevsim.system_message import SysMessage
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Gen(BehaviorModel):
|
|
100
|
+
def __init__(self, name):
|
|
101
|
+
super().__init__(name)
|
|
102
|
+
self.init_state("Generate")
|
|
103
|
+
self.insert_state("Generate", 1)
|
|
104
|
+
self.insert_output_port("out")
|
|
105
|
+
|
|
106
|
+
def ext_trans(self, port, msg): pass
|
|
107
|
+
def int_trans(self): pass
|
|
108
|
+
def output(self, md):
|
|
109
|
+
msg = SysMessage(self.get_name(), "out")
|
|
110
|
+
msg.insert("tick")
|
|
111
|
+
md.insert_message(msg)
|
|
112
|
+
def time_advance(self):
|
|
113
|
+
return 1
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class Sink(BehaviorModel):
|
|
117
|
+
def __init__(self, name):
|
|
118
|
+
super().__init__(name)
|
|
119
|
+
self.init_state("Idle")
|
|
120
|
+
self.insert_state("Idle", Infinite)
|
|
121
|
+
self.insert_input_port("in")
|
|
122
|
+
|
|
123
|
+
def ext_trans(self, port, msg):
|
|
124
|
+
print(f"received: {msg.retrieve()}")
|
|
125
|
+
def int_trans(self): pass
|
|
126
|
+
def output(self, md): pass
|
|
127
|
+
def time_advance(self):
|
|
128
|
+
return Infinite
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
se = SysExecutor(1, ex_mode=ExecutionType.V_TIME)
|
|
132
|
+
gen = Gen("g")
|
|
133
|
+
sink = Sink("s")
|
|
134
|
+
se.register_entity(gen)
|
|
135
|
+
se.register_entity(sink)
|
|
136
|
+
se.coupling_relation(gen, "out", sink, "in")
|
|
137
|
+
se.simulate(5)
|
|
57
138
|
```
|
|
58
|
-
pip install -r requirements.txt
|
|
59
|
-
```
|
|
60
139
|
|
|
61
|
-
|
|
62
|
-
|
|
140
|
+
See the [quick-start guide](https://pyjevsim.readthedocs.io/en/latest/pyjevsim_quick_start.html)
|
|
141
|
+
for structural models, snapshots, and HLA stepped execution.
|
|
142
|
+
|
|
143
|
+
### Examples
|
|
63
144
|
|
|
64
|
-
|
|
65
|
-
The docs describe how to configure a simulation via pyjevsim's BehaviorModel and SysExecutor.
|
|
66
|
-
Check out the [documentation](link) to configure your simulation.
|
|
145
|
+
The [`examples/`](examples/) directory contains:
|
|
67
146
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
147
|
+
- **`banksim/`** — bank queue simulation demonstrating BehaviorModel,
|
|
148
|
+
StructuralModel, and snapshot/restore.
|
|
149
|
+
- **`atsim/`** — anti-torpedo simulator with self-propelled and
|
|
150
|
+
stationary decoy models.
|
|
151
|
+
- **`mwmsim/`** — municipal waste management agent-based model.
|
|
71
152
|
|
|
72
153
|
### Output messages are shared by reference
|
|
73
154
|
|
|
@@ -1,46 +1,127 @@
|
|
|
1
1
|
# pyjevsim
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/pyjevsim/)
|
|
4
|
+
[](https://pypi.org/project/pyjevsim/)
|
|
5
|
+
[](https://pyjevsim.readthedocs.io/en/latest/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
2
8
|
## Introduction
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
|
|
10
|
+
pyjevsim is a DEVS (discrete event system specification) modeling and
|
|
11
|
+
simulation environment with built-in journaling. It supports snapshot
|
|
12
|
+
and restore of individual models or the full simulation engine,
|
|
13
|
+
virtual-time and real-time execution, and HLA federate integration via
|
|
14
|
+
a stepped execution mode. Compatible with Python 3.10+.
|
|
15
|
+
|
|
16
|
+
Full documentation: <https://pyjevsim.readthedocs.io/en/latest/>
|
|
17
|
+
|
|
18
|
+
### What's new in 2.0
|
|
19
|
+
|
|
20
|
+
- **Two-phase tick.** `SysExecutor` evaluates every imminent model's
|
|
21
|
+
`output()` first, then routes outputs and applies transitions —
|
|
22
|
+
fixing confluent-event ordering under Parallel-DEVS semantics.
|
|
23
|
+
- **HLA stepped execution.** `step(granted_time)` and
|
|
24
|
+
`get_next_event_time()` let an IEEE 1516-2010 RTI federate drive
|
|
25
|
+
pyjevsim without owning the main loop.
|
|
26
|
+
- **V_TIME jump-to-next-event.** The virtual-time scheduler hops
|
|
27
|
+
directly to the next scheduled event instead of advancing by a fixed
|
|
28
|
+
`time_resolution`, eliminating idle ticks on sparse models.
|
|
29
|
+
- **Opt-in uncaught-message tracking** for debugging dangling outputs.
|
|
30
|
+
- **DEVStone benchmark suite** with cross-engine comparison adapters.
|
|
31
|
+
|
|
9
32
|
## Installing
|
|
10
|
-
|
|
33
|
+
|
|
34
|
+
From PyPI (recommended):
|
|
35
|
+
|
|
11
36
|
```
|
|
12
|
-
|
|
37
|
+
pip install pyjevsim
|
|
13
38
|
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
dill is an essential library for serializing models and simulation states and can be installed via.
|
|
39
|
+
|
|
40
|
+
From source:
|
|
41
|
+
|
|
18
42
|
```
|
|
19
|
-
|
|
43
|
+
git clone https://github.com/eventsim/pyjevsim
|
|
44
|
+
cd pyjevsim
|
|
45
|
+
pip install -e .
|
|
20
46
|
```
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
47
|
+
|
|
48
|
+
## Dependencies
|
|
49
|
+
|
|
50
|
+
- Python >= 3.10
|
|
51
|
+
- `dill >= 0.3.6` (installed automatically) — used for model
|
|
52
|
+
serialization and restoration.
|
|
53
|
+
|
|
54
|
+
`pytest` is required only to run the test suite and is declared under
|
|
55
|
+
the `dev` extra:
|
|
56
|
+
|
|
25
57
|
```
|
|
26
|
-
pip install
|
|
58
|
+
pip install pyjevsim[dev]
|
|
27
59
|
```
|
|
28
|
-
|
|
29
|
-
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
A minimal generator → sink simulation:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from pyjevsim.behavior_model import BehaviorModel
|
|
67
|
+
from pyjevsim.definition import ExecutionType, Infinite
|
|
68
|
+
from pyjevsim.system_executor import SysExecutor
|
|
69
|
+
from pyjevsim.system_message import SysMessage
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Gen(BehaviorModel):
|
|
73
|
+
def __init__(self, name):
|
|
74
|
+
super().__init__(name)
|
|
75
|
+
self.init_state("Generate")
|
|
76
|
+
self.insert_state("Generate", 1)
|
|
77
|
+
self.insert_output_port("out")
|
|
78
|
+
|
|
79
|
+
def ext_trans(self, port, msg): pass
|
|
80
|
+
def int_trans(self): pass
|
|
81
|
+
def output(self, md):
|
|
82
|
+
msg = SysMessage(self.get_name(), "out")
|
|
83
|
+
msg.insert("tick")
|
|
84
|
+
md.insert_message(msg)
|
|
85
|
+
def time_advance(self):
|
|
86
|
+
return 1
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Sink(BehaviorModel):
|
|
90
|
+
def __init__(self, name):
|
|
91
|
+
super().__init__(name)
|
|
92
|
+
self.init_state("Idle")
|
|
93
|
+
self.insert_state("Idle", Infinite)
|
|
94
|
+
self.insert_input_port("in")
|
|
95
|
+
|
|
96
|
+
def ext_trans(self, port, msg):
|
|
97
|
+
print(f"received: {msg.retrieve()}")
|
|
98
|
+
def int_trans(self): pass
|
|
99
|
+
def output(self, md): pass
|
|
100
|
+
def time_advance(self):
|
|
101
|
+
return Infinite
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
se = SysExecutor(1, ex_mode=ExecutionType.V_TIME)
|
|
105
|
+
gen = Gen("g")
|
|
106
|
+
sink = Sink("s")
|
|
107
|
+
se.register_entity(gen)
|
|
108
|
+
se.register_entity(sink)
|
|
109
|
+
se.coupling_relation(gen, "out", sink, "in")
|
|
110
|
+
se.simulate(5)
|
|
30
111
|
```
|
|
31
|
-
pip install -r requirements.txt
|
|
32
|
-
```
|
|
33
112
|
|
|
34
|
-
|
|
35
|
-
|
|
113
|
+
See the [quick-start guide](https://pyjevsim.readthedocs.io/en/latest/pyjevsim_quick_start.html)
|
|
114
|
+
for structural models, snapshots, and HLA stepped execution.
|
|
115
|
+
|
|
116
|
+
### Examples
|
|
36
117
|
|
|
37
|
-
|
|
38
|
-
The docs describe how to configure a simulation via pyjevsim's BehaviorModel and SysExecutor.
|
|
39
|
-
Check out the [documentation](link) to configure your simulation.
|
|
118
|
+
The [`examples/`](examples/) directory contains:
|
|
40
119
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
120
|
+
- **`banksim/`** — bank queue simulation demonstrating BehaviorModel,
|
|
121
|
+
StructuralModel, and snapshot/restore.
|
|
122
|
+
- **`atsim/`** — anti-torpedo simulator with self-propelled and
|
|
123
|
+
stationary decoy models.
|
|
124
|
+
- **`mwmsim/`** — municipal waste management agent-based model.
|
|
44
125
|
|
|
45
126
|
### Output messages are shared by reference
|
|
46
127
|
|
|
@@ -5,7 +5,7 @@ Copyright (c) 2021-2024 Hanbat National University
|
|
|
5
5
|
License: MIT. The full license text is available at:
|
|
6
6
|
https://github.com/eventsim/pyjevsim/blob/main/LICENSE
|
|
7
7
|
|
|
8
|
-
This module contains a
|
|
8
|
+
This module contains a BehaviorModel object that allows you to implement the Discrete Event System Specification AtomicModel.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from abc import abstractmethod
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: Changbeom Choi (@cbchoi)
|
|
3
|
+
Copyright (c) 2014-2020 Handong Global University
|
|
4
|
+
Copyright (c) 2021-2024 Hanbat National University
|
|
5
|
+
License: MIT. The full license text is available at:
|
|
6
|
+
https://github.com/eventsim/pyjevsim/blob/main/LICENSE
|
|
7
|
+
|
|
8
|
+
This module contains a StructuralModel object that allows you to implement the Discrete Event System Specification CoupledModel.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .core_model import CoreModel
|
|
12
|
+
from .definition import ModelType
|
|
13
|
+
from .system_message import SysMessage
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class StructuralModel(CoreModel):
|
|
17
|
+
"""A DEVS coupled model: a container that aggregates child models and
|
|
18
|
+
declares the message flow between them.
|
|
19
|
+
|
|
20
|
+
A StructuralModel does **not** define its own state, transition, or
|
|
21
|
+
output behavior. Its job is to expose external input / output ports,
|
|
22
|
+
register child models (atomic or structural), and declare port-level
|
|
23
|
+
coupling relations. ``SysExecutor`` flattens these couplings when
|
|
24
|
+
routing messages so a hierarchical graph behaves identically to a
|
|
25
|
+
flattened one.
|
|
26
|
+
|
|
27
|
+
Three coupling patterns are supported through the same
|
|
28
|
+
:py:meth:`coupling_relation` call:
|
|
29
|
+
|
|
30
|
+
- **External Input Coupling (EIC):** ``self -> child.in_port``
|
|
31
|
+
- **Internal Coupling (IC):** ``child_a.out -> child_b.in``
|
|
32
|
+
- **External Output Coupling (EOC):** ``child.out -> self``
|
|
33
|
+
|
|
34
|
+
See :doc:`pyjevsim_quick_start` for a complete example.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def __init__(self, _name=""):
|
|
38
|
+
"""Initializes a StructuralModel.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
_name (str): Identifier used by ``SysExecutor`` for routing
|
|
42
|
+
and by hierarchical lookup. Must be unique within its
|
|
43
|
+
parent scope.
|
|
44
|
+
"""
|
|
45
|
+
super().__init__(_name, ModelType.STRUCTURAL)
|
|
46
|
+
|
|
47
|
+
self.model_map = {} # name -> child model
|
|
48
|
+
self.port_map = {} # (src_obj, src_port) -> [(dst_obj, dst_port), ...]
|
|
49
|
+
|
|
50
|
+
def register_entity(self, obj):
|
|
51
|
+
"""Registers a child model under this structural model.
|
|
52
|
+
|
|
53
|
+
The child is keyed by ``obj.get_name()``; registering a second
|
|
54
|
+
model with the same name overwrites the first.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
obj: An ``AtomicModel``, ``BehaviorModel``, or
|
|
58
|
+
``StructuralModel`` instance to add as a child.
|
|
59
|
+
"""
|
|
60
|
+
self.model_map[obj.get_name()] = obj
|
|
61
|
+
|
|
62
|
+
def remove_model(self, obj):
|
|
63
|
+
"""Removes a child model previously added with
|
|
64
|
+
:py:meth:`register_entity`.
|
|
65
|
+
|
|
66
|
+
Existing coupling entries that reference ``obj`` are **not**
|
|
67
|
+
cleaned up automatically; callers should drop them via
|
|
68
|
+
``port_map`` if needed.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
obj: The child model to remove. Must already be registered.
|
|
72
|
+
"""
|
|
73
|
+
del self.model_map[obj.get_name()]
|
|
74
|
+
|
|
75
|
+
def find_model(self, name):
|
|
76
|
+
"""Looks up a registered child model by name.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
name (str): The child model's name as returned by
|
|
80
|
+
``get_name()``.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The child model instance.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
KeyError: If no child with that name is registered.
|
|
87
|
+
"""
|
|
88
|
+
return self.model_map[name]
|
|
89
|
+
|
|
90
|
+
def get_models(self):
|
|
91
|
+
"""Returns the full ``name -> child model`` mapping.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
dict: The internal ``model_map``. Mutating the returned
|
|
95
|
+
dict mutates the structural model.
|
|
96
|
+
"""
|
|
97
|
+
return self.model_map
|
|
98
|
+
|
|
99
|
+
def coupling_relation(self, src_obj, src_port, dst_obj, dst_port):
|
|
100
|
+
"""Declares a coupling from one (model, port) to another.
|
|
101
|
+
|
|
102
|
+
The same ``(src_obj, src_port)`` may be coupled to multiple
|
|
103
|
+
destinations; each call appends a new destination. ``src_obj``
|
|
104
|
+
or ``dst_obj`` may be ``self`` to express EIC or EOC.
|
|
105
|
+
|
|
106
|
+
Note: messages are propagated **by reference**; downstream
|
|
107
|
+
receivers should treat them as immutable. See
|
|
108
|
+
:doc:`pyjevsim_quick_start` (Output Messages Are Shared by
|
|
109
|
+
Reference) for the rationale.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
src_obj: Source model (or ``self`` for EIC).
|
|
113
|
+
src_port (str): Source port name.
|
|
114
|
+
dst_obj: Destination model (or ``self`` for EOC).
|
|
115
|
+
dst_port (str): Destination port name.
|
|
116
|
+
"""
|
|
117
|
+
src = (src_obj, src_port)
|
|
118
|
+
dst = (dst_obj, dst_port)
|
|
119
|
+
|
|
120
|
+
if src not in self.port_map:
|
|
121
|
+
self.port_map[src] = []
|
|
122
|
+
|
|
123
|
+
self.port_map[src].append(dst)
|
|
124
|
+
|
|
125
|
+
def get_couplings(self):
|
|
126
|
+
"""Returns the coupling map.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
dict: ``{(src_obj, src_port): [(dst_obj, dst_port), ...]}``
|
|
130
|
+
describing every declared coupling under this structural
|
|
131
|
+
model.
|
|
132
|
+
"""
|
|
133
|
+
return self.port_map
|
|
@@ -27,7 +27,28 @@ from .termination_manager import TerminationManager
|
|
|
27
27
|
from .message_deliverer import MessageDeliverer
|
|
28
28
|
|
|
29
29
|
class SysExecutor(CoreModel):
|
|
30
|
-
"""
|
|
30
|
+
"""The pyjevsim simulation engine.
|
|
31
|
+
|
|
32
|
+
``SysExecutor`` owns the global simulated clock, the future-event
|
|
33
|
+
list (FEL), the coupling graph, and the lifecycle of registered
|
|
34
|
+
executors. It runs each simulated instant as a two-phase tick —
|
|
35
|
+
Phase A drains every imminent model's ``output()`` against its
|
|
36
|
+
pre-transition state; Phase B routes outputs through coupling and
|
|
37
|
+
applies ``int_trans`` / ``ext_trans`` / ``con_trans`` per
|
|
38
|
+
Parallel-DEVS semantics.
|
|
39
|
+
|
|
40
|
+
Three execution modes are supported via :class:`ExecutionType`:
|
|
41
|
+
|
|
42
|
+
- ``V_TIME`` — virtual-time, jump-to-next-event. ``simulate()``
|
|
43
|
+
drives the loop and ``global_time`` hops directly to the next
|
|
44
|
+
scheduled event.
|
|
45
|
+
- ``R_TIME`` — real-time, ``time_resolution``-stepped with a
|
|
46
|
+
``time.sleep`` to match wall-clock pace.
|
|
47
|
+
- ``HLA_TIME`` — federate-driven. The executor does not advance
|
|
48
|
+
time on its own; an HLA ambassador calls
|
|
49
|
+
:py:meth:`get_next_event_time` then :py:meth:`step` to grant
|
|
50
|
+
cascade rounds inside an RTI-issued time grant.
|
|
51
|
+
"""
|
|
31
52
|
|
|
32
53
|
EXTERNAL_SRC = "SRC"
|
|
33
54
|
EXTERNAL_DST = "DST"
|
|
@@ -41,7 +62,11 @@ class SysExecutor(CoreModel):
|
|
|
41
62
|
Args:
|
|
42
63
|
_time_resolution (float): The time resolution for the simulation
|
|
43
64
|
_sim_name (str, optional): The name of the simulation
|
|
44
|
-
ex_mode (
|
|
65
|
+
ex_mode (ExecutionType): The execution mode — one of
|
|
66
|
+
``V_TIME`` (virtual time, jump-to-next-event),
|
|
67
|
+
``R_TIME`` (real time, ``time_resolution``-stepped),
|
|
68
|
+
or ``HLA_TIME`` (federate-driven via
|
|
69
|
+
:py:meth:`step`).
|
|
45
70
|
snapshot_manager (ModelSnapshotManager, optional): Manages SnapshotExecutor
|
|
46
71
|
track_uncaught (bool, optional): When True, output messages
|
|
47
72
|
emitted to ports with no downstream coupling are routed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyjevsim
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1
|
|
4
4
|
Summary: A DEVS(Discrete Event System Specification) Modeling & Simulation environment with journaling functionality
|
|
5
5
|
Author-email: Changbeom Choi <me@cbchoi.info>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -26,48 +26,129 @@ Requires-Dist: pytest>=7.0; extra == "dev"
|
|
|
26
26
|
Dynamic: license-file
|
|
27
27
|
|
|
28
28
|
# pyjevsim
|
|
29
|
+
|
|
30
|
+
[](https://pypi.org/project/pyjevsim/)
|
|
31
|
+
[](https://pypi.org/project/pyjevsim/)
|
|
32
|
+
[](https://pyjevsim.readthedocs.io/en/latest/)
|
|
33
|
+
[](LICENSE)
|
|
34
|
+
|
|
29
35
|
## Introduction
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
pyjevsim is a DEVS (discrete event system specification) modeling and
|
|
38
|
+
simulation environment with built-in journaling. It supports snapshot
|
|
39
|
+
and restore of individual models or the full simulation engine,
|
|
40
|
+
virtual-time and real-time execution, and HLA federate integration via
|
|
41
|
+
a stepped execution mode. Compatible with Python 3.10+.
|
|
42
|
+
|
|
43
|
+
Full documentation: <https://pyjevsim.readthedocs.io/en/latest/>
|
|
44
|
+
|
|
45
|
+
### What's new in 2.0
|
|
46
|
+
|
|
47
|
+
- **Two-phase tick.** `SysExecutor` evaluates every imminent model's
|
|
48
|
+
`output()` first, then routes outputs and applies transitions —
|
|
49
|
+
fixing confluent-event ordering under Parallel-DEVS semantics.
|
|
50
|
+
- **HLA stepped execution.** `step(granted_time)` and
|
|
51
|
+
`get_next_event_time()` let an IEEE 1516-2010 RTI federate drive
|
|
52
|
+
pyjevsim without owning the main loop.
|
|
53
|
+
- **V_TIME jump-to-next-event.** The virtual-time scheduler hops
|
|
54
|
+
directly to the next scheduled event instead of advancing by a fixed
|
|
55
|
+
`time_resolution`, eliminating idle ticks on sparse models.
|
|
56
|
+
- **Opt-in uncaught-message tracking** for debugging dangling outputs.
|
|
57
|
+
- **DEVStone benchmark suite** with cross-engine comparison adapters.
|
|
58
|
+
|
|
36
59
|
## Installing
|
|
37
|
-
|
|
60
|
+
|
|
61
|
+
From PyPI (recommended):
|
|
62
|
+
|
|
38
63
|
```
|
|
39
|
-
|
|
64
|
+
pip install pyjevsim
|
|
40
65
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
dill is an essential library for serializing models and simulation states and can be installed via.
|
|
66
|
+
|
|
67
|
+
From source:
|
|
68
|
+
|
|
45
69
|
```
|
|
46
|
-
|
|
70
|
+
git clone https://github.com/eventsim/pyjevsim
|
|
71
|
+
cd pyjevsim
|
|
72
|
+
pip install -e .
|
|
47
73
|
```
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
74
|
+
|
|
75
|
+
## Dependencies
|
|
76
|
+
|
|
77
|
+
- Python >= 3.10
|
|
78
|
+
- `dill >= 0.3.6` (installed automatically) — used for model
|
|
79
|
+
serialization and restoration.
|
|
80
|
+
|
|
81
|
+
`pytest` is required only to run the test suite and is declared under
|
|
82
|
+
the `dev` extra:
|
|
83
|
+
|
|
52
84
|
```
|
|
53
|
-
pip install
|
|
85
|
+
pip install pyjevsim[dev]
|
|
54
86
|
```
|
|
55
|
-
|
|
56
|
-
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
A minimal generator → sink simulation:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from pyjevsim.behavior_model import BehaviorModel
|
|
94
|
+
from pyjevsim.definition import ExecutionType, Infinite
|
|
95
|
+
from pyjevsim.system_executor import SysExecutor
|
|
96
|
+
from pyjevsim.system_message import SysMessage
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Gen(BehaviorModel):
|
|
100
|
+
def __init__(self, name):
|
|
101
|
+
super().__init__(name)
|
|
102
|
+
self.init_state("Generate")
|
|
103
|
+
self.insert_state("Generate", 1)
|
|
104
|
+
self.insert_output_port("out")
|
|
105
|
+
|
|
106
|
+
def ext_trans(self, port, msg): pass
|
|
107
|
+
def int_trans(self): pass
|
|
108
|
+
def output(self, md):
|
|
109
|
+
msg = SysMessage(self.get_name(), "out")
|
|
110
|
+
msg.insert("tick")
|
|
111
|
+
md.insert_message(msg)
|
|
112
|
+
def time_advance(self):
|
|
113
|
+
return 1
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class Sink(BehaviorModel):
|
|
117
|
+
def __init__(self, name):
|
|
118
|
+
super().__init__(name)
|
|
119
|
+
self.init_state("Idle")
|
|
120
|
+
self.insert_state("Idle", Infinite)
|
|
121
|
+
self.insert_input_port("in")
|
|
122
|
+
|
|
123
|
+
def ext_trans(self, port, msg):
|
|
124
|
+
print(f"received: {msg.retrieve()}")
|
|
125
|
+
def int_trans(self): pass
|
|
126
|
+
def output(self, md): pass
|
|
127
|
+
def time_advance(self):
|
|
128
|
+
return Infinite
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
se = SysExecutor(1, ex_mode=ExecutionType.V_TIME)
|
|
132
|
+
gen = Gen("g")
|
|
133
|
+
sink = Sink("s")
|
|
134
|
+
se.register_entity(gen)
|
|
135
|
+
se.register_entity(sink)
|
|
136
|
+
se.coupling_relation(gen, "out", sink, "in")
|
|
137
|
+
se.simulate(5)
|
|
57
138
|
```
|
|
58
|
-
pip install -r requirements.txt
|
|
59
|
-
```
|
|
60
139
|
|
|
61
|
-
|
|
62
|
-
|
|
140
|
+
See the [quick-start guide](https://pyjevsim.readthedocs.io/en/latest/pyjevsim_quick_start.html)
|
|
141
|
+
for structural models, snapshots, and HLA stepped execution.
|
|
142
|
+
|
|
143
|
+
### Examples
|
|
63
144
|
|
|
64
|
-
|
|
65
|
-
The docs describe how to configure a simulation via pyjevsim's BehaviorModel and SysExecutor.
|
|
66
|
-
Check out the [documentation](link) to configure your simulation.
|
|
145
|
+
The [`examples/`](examples/) directory contains:
|
|
67
146
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
147
|
+
- **`banksim/`** — bank queue simulation demonstrating BehaviorModel,
|
|
148
|
+
StructuralModel, and snapshot/restore.
|
|
149
|
+
- **`atsim/`** — anti-torpedo simulator with self-propelled and
|
|
150
|
+
stationary decoy models.
|
|
151
|
+
- **`mwmsim/`** — municipal waste management agent-based model.
|
|
71
152
|
|
|
72
153
|
### Output messages are shared by reference
|
|
73
154
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyjevsim"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.1"
|
|
8
8
|
description = "A DEVS(Discrete Event System Specification) Modeling & Simulation environment with journaling functionality"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Author: Changbeom Choi (@cbchoi)
|
|
3
|
-
Copyright (c) 2014-2020 Handong Global University
|
|
4
|
-
Copyright (c) 2021-2024 Hanbat National University
|
|
5
|
-
License: MIT. The full license text is available at:
|
|
6
|
-
https://github.com/eventsim/pyjevsim/blob/main/LICENSE
|
|
7
|
-
|
|
8
|
-
This module contains a StructuralModel object that allows you to implement the Discrete Event System Specification CoupledModel.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
from .core_model import CoreModel
|
|
12
|
-
from .definition import ModelType
|
|
13
|
-
from .system_message import SysMessage
|
|
14
|
-
|
|
15
|
-
class StructuralModel(CoreModel):
|
|
16
|
-
def __init__(self, _name=""):
|
|
17
|
-
super().__init__(_name, ModelType.STRUCTURAL)
|
|
18
|
-
|
|
19
|
-
self.model_map = {}#(name, model)
|
|
20
|
-
|
|
21
|
-
self.port_map = {}
|
|
22
|
-
|
|
23
|
-
def register_entity(self, obj):
|
|
24
|
-
self.model_map[obj.get_name()] = obj
|
|
25
|
-
|
|
26
|
-
def remove_model(self, obj) :
|
|
27
|
-
del self.model_map[obj.get_name()]
|
|
28
|
-
|
|
29
|
-
def find_model(self, name) :
|
|
30
|
-
return self.model_map[name]
|
|
31
|
-
|
|
32
|
-
def get_models(self):
|
|
33
|
-
return self.model_map
|
|
34
|
-
|
|
35
|
-
def coupling_relation(self, src_obj, src_port, dst_obj, dst_port):
|
|
36
|
-
src = (src_obj, src_port)
|
|
37
|
-
dst = (dst_obj, dst_port)
|
|
38
|
-
|
|
39
|
-
# If the source is not in the map, initialize it with an empty list
|
|
40
|
-
if src not in self.port_map:
|
|
41
|
-
self.port_map[src] = []
|
|
42
|
-
|
|
43
|
-
# Add the destination to the source's list of destinations
|
|
44
|
-
self.port_map[src].append(dst)
|
|
45
|
-
pass
|
|
46
|
-
|
|
47
|
-
def get_couplings(self) :
|
|
48
|
-
return self.port_map
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|