pyjevsim 1.0.0__py3-none-any.whl

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/definition.py ADDED
@@ -0,0 +1,102 @@
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 definitions for pyjevsim's const and type.
9
+ """
10
+ from enum import Enum
11
+
12
+ # Define an infinite value
13
+ Infinite = float("inf")
14
+
15
+ class AttributeType(Enum):
16
+ """Enum for attribute types."""
17
+ ASPECT = 1
18
+ RUNTIME = 2
19
+ UNKNOWN_TYPE = -1
20
+
21
+ @staticmethod
22
+ def resolve_type_from_str(name):
23
+ """Resolves an attribute type from a string.
24
+
25
+ Args:
26
+ name (str): The name of the attribute type
27
+ Returns:
28
+ AttributeType: The resolved attribute type
29
+ """
30
+
31
+ if "ASPECT" == name.upper():
32
+ return AttributeType.ASPECT
33
+ elif "RUNTIME" == name.upper():
34
+ return AttributeType.RUNTIME
35
+ else:
36
+ return AttributeType.UNKNOWN_TYPE
37
+
38
+ @staticmethod
39
+ def resolve_type_from_enum(enum):
40
+ """Resolves an attribute type to a string.
41
+
42
+ Args:
43
+ enum (AttributeType): The attribute type enum
44
+ Returns:
45
+ str: The name of the attribute type
46
+ """
47
+ if enum == AttributeType.ASPECT:
48
+ return "ASPECT"
49
+ elif enum == AttributeType.RUNTIME:
50
+ return "RUNTIME"
51
+ else:
52
+ return "UNKNOWN"
53
+
54
+ class SimulationMode(Enum):
55
+ """Enum for simulation modes."""
56
+
57
+ SIMULATION_IDLE = (
58
+ 0 # Simulation Engine is instantiated but simulation is not running
59
+ )
60
+ SIMULATION_RUNNING = 1 # Simulation Engine is instantiated, simulation is running
61
+ SIMULATION_TERMINATED = (
62
+ 2 # Simulation Engine is instantiated but simulation is terminated
63
+ )
64
+ SIMULATION_PAUSE = 3 # Simulation Engine is instantiated, simulation paused
65
+ SIMULATION_UNKNOWN = -1 # Simulation Engine went to abnormal state
66
+
67
+
68
+ class ModelType(Enum):
69
+ """Enum for model types."""
70
+
71
+ BEHAVIORAL = 0 #BehaviorModel type : DEVS Atomic Model
72
+ STRUCTURAL = 1 #StructuralModel type : DEVS Coupled Model
73
+ UTILITY = 2
74
+
75
+
76
+ class ExecutionType(Enum):
77
+ """Enum for execution types."""
78
+
79
+ R_TIME = 0 #Real time
80
+ V_TIME = 1 #Virtual time
81
+ HLA_TIME = 2 #HLA/RTI-controlled time (externally driven)
82
+
83
+
84
+ class SingletonType(object):
85
+ """A decorator for making a class a singleton."""
86
+
87
+ def __call__(self, cls, *args, **kwargs):
88
+ """Creates or returns the singleton instance of the class.
89
+
90
+ Args:
91
+ cls (type): The class to be instantiated
92
+ *args: Variable length argument list
93
+ **kwargs: Arbitrary keyword arguments
94
+
95
+ Returns:
96
+ object: The singleton instance of the class
97
+ """
98
+ try:
99
+ return cls.__instance
100
+ except AttributeError:
101
+ cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
102
+ return cls.__instance
pyjevsim/executor.py ADDED
@@ -0,0 +1,27 @@
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 Executor, the parent class of all Executor Types.
9
+ """
10
+
11
+ class Executor:
12
+ """Base class for executors."""
13
+ def __init__(self, itime, dtime, ename, model, parent):
14
+ """
15
+ Args:
16
+ itime (float): Instance creation time
17
+ dtime (float): Destruction time
18
+ ename (str): Engine name
19
+ """
20
+ self.engine_name = ename
21
+ self._instance_t = itime
22
+ self._destruct_t = dtime
23
+ self.model = model
24
+ self.parent = parent
25
+
26
+ def __lt__(self, other):
27
+ return (self.request_time, self.get_obj_id()) < (other.request_time, other.get_obj_id())
@@ -0,0 +1,77 @@
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 an ExecutorFactory that decorates an object of type Model into an Executor that is executable by a SysExecutor.
9
+ """
10
+
11
+ from .definition import ModelType
12
+ from .behavior_executor import BehaviorExecutor
13
+
14
+ class ExecutorFactory:
15
+ """Factory class to create different types of executors."""
16
+
17
+ def __init__(self):
18
+ pass
19
+
20
+ def create_executor(self, global_time, ins_t, des_t, en_name, model, parent
21
+ ):
22
+ """Creates an executor based on the model type.
23
+
24
+ Args:
25
+ global_time (float): Global simulation time
26
+ ins_t (float): Instance creation time
27
+ des_t (float): Destruction time
28
+ en_name (str): Engine name
29
+ model(ModelType.BEHAVIORAL of ModelType.STRUCTURAL): The model to execute
30
+
31
+ Returns:
32
+ Executor: The created executor
33
+ """
34
+ if model.get_model_type() == ModelType.BEHAVIORAL:
35
+ return self.create_behavior_executor(
36
+ global_time, ins_t, des_t, en_name, model, parent
37
+ )
38
+ elif model.get_model_type() == ModelType.STRUCTURAL:
39
+ return self.create_structural_executor(
40
+ global_time, ins_t, des_t, en_name, model, parent
41
+ )
42
+ else:
43
+ return None
44
+
45
+ def create_behavior_executor(self, _, ins_t, des_t, en_name, model, parent):
46
+ """Create BehaviorModelexecutor
47
+
48
+ Args:
49
+ _ (float): Unused global time
50
+ ins_t (float): Instance creation time
51
+ des_t (float): Destruction time
52
+ en_name (str): SysExecutor name
53
+ model (BehaviorModel): Behavior model to execute
54
+
55
+ Returns:
56
+ BehaviorModelExecutor: The created BehaviorModelexecutor
57
+ """
58
+ return BehaviorExecutor(ins_t, des_t, en_name, model, parent)
59
+
60
+ def create_structural_executor(self, global_time, ins_t, des_t, en_name, model, parent):
61
+ """Create StructuralModelExecutor
62
+
63
+ Args:
64
+ global_time (float): Global simulation time
65
+ ins_t (float): Instance creation time
66
+ des_t (float): Destruction time
67
+ en_name (str): SysExecutor name
68
+ model (StructuralModel): StructuralModel to execute
69
+
70
+ Returns:
71
+ StructuralModelExecutor: created StructuralModelExecutor
72
+ """
73
+ from .structural_executor import StructuralExecutor
74
+ return StructuralExecutor(
75
+ global_time, ins_t, des_t, en_name, model, parent, self
76
+ )
77
+
pyjevsim/exgen.py ADDED
@@ -0,0 +1,116 @@
1
+ relay_example = """from pyjevsim import BehaviorModel, SysExecutor, SysMessage, Infinite, ExecutionType
2
+ import datetime
3
+
4
+ class PEG(BehaviorModel):
5
+ def __init__(self, name):
6
+ BehaviorModel.__init__(self, name)
7
+ self.init_state("Wait")
8
+ self.insert_state("Wait", Infinite)
9
+ self.insert_state("Generate", 1)
10
+
11
+ self.insert_input_port("start")
12
+ self.insert_output_port("process")
13
+
14
+ def ext_trans(self, port, msg):
15
+ if port == "start":
16
+ print(f"[Gen][IN]: {datetime.datetime.now()}")
17
+ self._cur_state = "Generate"
18
+
19
+ def output(self, msg_deliver):
20
+ msg = SysMessage(self.get_name(), "process")
21
+ msg.insert(f"[Gen][OUT]: {datetime.datetime.now()}")
22
+ msg_deliver.insert_message(msg)
23
+
24
+ def int_trans(self):
25
+ if self._cur_state == "Generate":
26
+ self._cur_state = "Generate"
27
+
28
+ class MsgRecv(BehaviorModel):
29
+ def __init__(self, name):
30
+ BehaviorModel.__init__(self, name)
31
+
32
+ self.init_state("Wait")
33
+ self.insert_state("Wait", Infinite)
34
+ self.insert_input_port("recv")
35
+
36
+ def ext_trans(self, port, msg):
37
+ if port == "recv":
38
+ print(f"[MsgRecv][IN]: {datetime.datetime.now()}")
39
+ data = msg.retrieve()
40
+ print(data[0])
41
+ self._cur_state = "Wait"
42
+
43
+ def output(self, msg_deliver):
44
+ pass
45
+
46
+ def int_trans(self):
47
+ if self._cur_state == "Wait":
48
+ self._cur_state = "Wait"
49
+
50
+ # System Executor Initialization
51
+ se = SysExecutor(1, ex_mode=ExecutionType.R_TIME)
52
+ se.insert_input_port("start")
53
+ gen = PEG("Gen")
54
+ se.register_entity(gen)
55
+ proc = MsgRecv("Proc")
56
+ se.register_entity(proc)
57
+ se.coupling_relation(None, "start", gen, "start")
58
+ se.coupling_relation(gen, "process", proc, "recv")
59
+ se.insert_external_event("start", None)
60
+ se.simulate(5)
61
+ """
62
+
63
+ periodic_example = """from pyjevsim import BehaviorModel, SysExecutor, Infinite, ExecutionType
64
+ import datetime
65
+
66
+ class PEx(BehaviorModel):
67
+ def __init__(self, name):
68
+ BehaviorModel.__init__(self, name)
69
+ self.init_state("Wait")
70
+ self.insert_state("Wait", Infinite)
71
+ self.insert_state("Generate", 1)
72
+
73
+ self.insert_input_port("start")
74
+
75
+ def ext_trans(self, port, msg):
76
+ if port == "start":
77
+ print(f"[Gen][IN]: {datetime.datetime.now()}")
78
+ self._cur_state = "Generate"
79
+
80
+ def output(self, msg_deliver):
81
+ print(f"[Gen][OUT]: {datetime.datetime.now()}")
82
+
83
+ def int_trans(self):
84
+ if self._cur_state == "Generate":
85
+ self._cur_state = "Generate"
86
+
87
+
88
+ se = SysExecutor(1, ex_mode=ExecutionType.R_TIME)
89
+ se.insert_input_port("start")
90
+ gen = PEx("Gen")
91
+ se.register_entity(gen)
92
+ se.coupling_relation(None, "start", gen, "start")
93
+ se.insert_external_event("start", None)
94
+ se.simulate(5)
95
+ """
96
+
97
+ usage = """
98
+ Usage: python -m pyjevsim.exgen [example]
99
+
100
+ types of example:
101
+ periodic:\t Prints event log periodically
102
+ relay: \t A model sends an output event and another model receives the event
103
+ """
104
+ import sys
105
+ if len(sys.argv) != 2:
106
+ print(usage)
107
+ elif sys.argv[1] == "relay":
108
+ with open("example_relay.py", "w") as f:
109
+ f.write(relay_example)
110
+ print("Generated: example_relay.py")
111
+ elif sys.argv[1] == "periodic":
112
+ with open("example_periodic.py", "w") as f:
113
+ f.write(periodic_example)
114
+ print("Generated: example_periodic.py")
115
+ else:
116
+ print(usage)
@@ -0,0 +1,44 @@
1
+ from .definition import *
2
+ from .system_message import SysMessage
3
+
4
+ class MessageDeliverer:
5
+ def __init__(self):
6
+ self.data_list = []
7
+
8
+ def insert_message(self, msg):
9
+ """
10
+ Inserts a message into the data list.
11
+
12
+ Args:
13
+ msg: Message object to be inserted.
14
+ """
15
+ self.data_list.append(msg) #SysMessage type
16
+
17
+ #self.data_list.sort(key=lambda m: m.get_scheduled_time())
18
+
19
+ def has_contents(self):
20
+ """
21
+ Checks if the data list contains any messages.
22
+
23
+ Returns:
24
+ bool: True if the list is not empty, otherwise False.
25
+ """
26
+ return len(self.data_list) > 0
27
+
28
+ def get_contents(self):
29
+ """
30
+ Retrieves the list of messages.
31
+
32
+ Returns:
33
+ list: The list of Message objects.
34
+ """
35
+ return self.data_list
36
+
37
+ def get_first_event_time(self):
38
+ """
39
+ Retrieves the scheduled time of the first message in the list.
40
+
41
+ Returns:
42
+ float: Scheduled time of the first message or Infinity if the list is empty.
43
+ """
44
+ return float("inf") if not self.data_list else self.data_list[0].get_scheduled_time()
@@ -0,0 +1,116 @@
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
+ """
9
+ from dill import load, loads
10
+ from .definition import ModelType, ExecutionType
11
+ import json
12
+ import ast
13
+ from .system_executor import SysExecutor
14
+
15
+ class RestoreHandler():
16
+ """ Restore a snapshotted model or project.
17
+ """
18
+ def __init__(self, t_resol=1, ex_mode=ExecutionType.V_TIME, name="project", path="./snapshot"):
19
+ """
20
+ Initializes the RestoreHandler with time resolution, execution mode, name, and path.
21
+
22
+ Args:
23
+ t_resol (float): Time resolution
24
+ ex_mode (R_TIME or V_TIME): Execution mode(Real time or Virtual time)
25
+ name (str): Name of SysExecutor
26
+ path (str, optional): Path to load snapshots
27
+ """
28
+ self.path = f"{path}/{name}"
29
+ self.sim_name = name
30
+ self.engine = SysExecutor(t_resol, name, ex_mode, snapshot_manager=None)
31
+ self.model_map = {}
32
+ pass
33
+
34
+ def restore_engine(self):
35
+ """
36
+ Sets up SysExecutor with the relation map and model map.
37
+ """
38
+ with open(f"{self.path}/relation_map.json", "r") as f:
39
+ relation = json.load(f)
40
+ relation = {ast.literal_eval(key): ast.literal_eval(value) for key, value in relation.items()}
41
+
42
+ model_list = {}
43
+ with open(f"{self.path}/model_map.json", "r") as f:
44
+ model_list = json.load(f)
45
+ model_list = model_list["model_name"]
46
+
47
+ self.load_models(model_list)
48
+ self.relations(relation)
49
+
50
+ def load_models(self, model_list):
51
+ """
52
+ Loads models from files and registers them with SysExecutor.
53
+
54
+ Args:
55
+ model_list (list): List of model names
56
+ """
57
+ for model_name in model_list:
58
+ with open(f"{self.path}/{model_name}.simx", "rb") as f:
59
+ model = load(f)
60
+
61
+ self.model_map[model_name] = model["data"]
62
+ self.engine.register_entity(model["data"])
63
+
64
+ def relations(self, relation_map):
65
+ """
66
+ Sets up coupling relations in SysExecutor.
67
+
68
+ Args:
69
+ relation_map (dict): The relation map / 관계 맵
70
+ """
71
+ for key, value in relation_map.items():
72
+ if key[0] in self.model_map.keys():
73
+ output_model = self.model_map[key[0]]
74
+ else:
75
+ output_model = self.engine
76
+ for model in value:
77
+ if model[0]:
78
+ input_model = self.model_map[model[0]]
79
+ else:
80
+ input_model = self.engine
81
+ self.engine.coupling_relation(output_model, key[1], input_model, model[1])
82
+
83
+ def get_engine(self):
84
+ """Returns the SysExecutor.
85
+
86
+ Returns:
87
+ Restored SysExecutor
88
+ """
89
+ self.restore_engine()
90
+ return self.engine
91
+
92
+ def load_snapshot(self, name, shotmodel):
93
+ """Loads BehaviorModel.
94
+
95
+ Args:
96
+ name (str): The name of Model
97
+ shotmodel (bytes): Binary data of the model snapshot
98
+
99
+ Returns:
100
+ object(BehaivorModel): The loaded model
101
+
102
+ Raises:
103
+ Exception: If the model type is not ModelType.BEHAVIORAL
104
+ """
105
+ model_info = loads(shotmodel)
106
+
107
+ if model_info["type"] != ModelType.BEHAVIORAL and model_info["type"] != ModelType.STRUCTURAL :
108
+ raise Exception(f"{model_info['name']} is not of Model type")
109
+
110
+ model = model_info["data"]
111
+
112
+ if name is not None:
113
+ model.set_name(name)
114
+
115
+ return model
116
+
@@ -0,0 +1,101 @@
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
+ from abc import abstractmethod, abstractstaticmethod
9
+
10
+ class SnapshotCondition:
11
+ """A class for filling in the snapshot condition of a model.
12
+ Users inherit from SnapshotCondition to fill in the model snapshot condition.
13
+ Snapshot conditions can be placed before or after functions in the behavior model.
14
+ """
15
+ @abstractstaticmethod
16
+ def create_executor(behavior_executor) :
17
+ """
18
+ This method is an abstractstatic method.
19
+ Specify the SnapshotCondition you created as the return value of this method.
20
+
21
+ Args:
22
+ behavior_executor (BehaviorExecutor): Set the BehaviorExecutor of the BehaviorModel you want to snapshot.
23
+ Returns:
24
+ SnapshotCondition : Returns the SnapshotCondition as configured by the user.
25
+ """
26
+ return SnapshotCondition(behavior_executor)
27
+
28
+ def __init__(self, behavior_executor):
29
+ """
30
+ Args:
31
+ behavior_executor (BehaviorExecutor): Set the BehaviorExecutor of the BehaviorModel you want to snapshot.
32
+ """
33
+ self.behavior_executor = behavior_executor
34
+
35
+ @abstractmethod
36
+ def snapshot_time_condition(self, global_time):
37
+ """Abstract method for snapshot time condition.
38
+
39
+ Args:
40
+ global_time (float): The global time / simulation time
41
+ """
42
+ return False
43
+
44
+ @abstractmethod
45
+ def snapshot_pre_condition_ext(self, port, msg, cur_state):
46
+ """Abstract method for pre-condition of external transition snapshot.
47
+
48
+ Args:
49
+ port (str): The port name
50
+ msg (SysMessage): The message
51
+ cur_state (str): The current state
52
+ """
53
+ return False
54
+
55
+ @abstractmethod
56
+ def snapshot_post_condition_ext(self, port, msg, cur_state):
57
+ """Abstract method for post-condition of external transition snapshot.
58
+
59
+ Args:
60
+ port (str): The port name
61
+ msg (SysMessage): The message
62
+ cur_state (str): The current state
63
+ """
64
+ return False
65
+
66
+ @abstractmethod
67
+ def snapshot_pre_condition_int(self, cur_state):
68
+ """Abstract method for pre-condition of internal transition snapshot.
69
+
70
+ Args:
71
+ cur_state (str): The current state
72
+ """
73
+ return False
74
+
75
+ @abstractmethod
76
+ def snapshot_post_condition_int(self, cur_state):
77
+ """Abstract method for post-condition of internal transition snapshot.
78
+
79
+ Args:
80
+ cur_state (str): The current state
81
+ """
82
+ return False
83
+
84
+ @abstractmethod
85
+ def snapshot_pre_condition_out(self, cur_state):
86
+ """Abstract method for pre-condition of output snapshot.
87
+
88
+ Args:
89
+ cur_state (str): The current state
90
+ """
91
+ return False
92
+
93
+ @abstractmethod
94
+ def snapshot_post_condition_out(self, msg, cur_state):
95
+ """Abstract method for post-condition of output snapshot.
96
+
97
+ Args:
98
+ msg (SysMessage): The message
99
+ cur_state (str): The current state
100
+ """
101
+ return False