Ver código fonte

Remove outliers from data when plotting. Devstone Models are now printable and dynamic LI and HI models now ignore the model at max depth

Snej69420 1 mês atrás
pai
commit
85fc113495
2 arquivos alterados com 47 adições e 19 exclusões
  1. 14 8
      devstone/compare.py
  2. 33 11
      devstone/pythonpdevs/devstone.py

+ 14 - 8
devstone/compare.py

@@ -5,20 +5,26 @@ import pandas as pd
 import matplotlib.pyplot as plt
 from pathlib import Path
 
-def load_and_filter(csv_path, fixed_param, fixed_value):
-    """Load a CSV file and filter rows by the fixed parameter."""
-    df = pd.read_csv(csv_path)
-    df = df[df[fixed_param] == fixed_value]
-    return df
-
 def process_files(csv_files, fixed_param, fixed_value):
     """Combine and average simulation times by the varying parameter."""
     results = {}
     varying_param = "depth" if fixed_param == "width" else "width"
 
     for path in csv_files:
-        df = load_and_filter(path, fixed_param, fixed_value)
-        # Average simulation times for identical setups
+        # df = pd.read_csv(path)
+        # df = df[df[fixed_param] == fixed_value]
+        # grouped = df.groupby(varying_param, as_index=False)["simulation_time"].mean()
+        # results[path.parent.name + "-" + path.stem] = grouped
+
+        df = pd.read_csv(path)
+        df = df[df[fixed_param] == fixed_value]
+
+        Q1 = df["simulation_time"].quantile(0.25)
+        Q3 = df["simulation_time"].quantile(0.75)
+        IQR = Q3 - Q1
+        lower_bound = Q1 - 1.5 * IQR
+        upper_bound = Q3 + 1.5 * IQR
+        df = df[(df["simulation_time"] >= lower_bound) & (df["simulation_time"] <= upper_bound)]
         grouped = df.groupby(varying_param, as_index=False)["simulation_time"].mean()
         results[path.parent.name + "-" + path.stem] = grouped
 

+ 33 - 11
devstone/pythonpdevs/devstone.py

@@ -37,12 +37,10 @@ class DelayedAtomic(AtomicDEVS):
 
     def outputFnc(self):
         if hasattr(self, "o_out") and self.o_out is not None:
-            print(f"{self.name}: outputFnc() called at t={self.elapsed}")
             return {self.o_out: [0]}
 
         # for DSDEVS LI2HI
         if len(self.out_ports) == 1 and self.out_ports[0].outline != []:
-            print(f"{self.name}: outputFnc() called at t={self.elapsed}")
             # print(f"{self.name}: should be last call!!")
             # print("Send to ", self.out_ports[0].outline)
             return {self.out_ports[0]: [0]}
@@ -116,6 +114,9 @@ class DEVStoneWrapper(CoupledDEVS, ABC):
         self.i_in = self.addInPort("i_in")
         self.o_out = self.addOutPort("o_out")
 
+        self.models = [] # stores all models part of the coupled model
+        # added to deal with DS DEVS which don't keep it all in the component_set
+
         if depth < 1:
             raise ValueError("Invalid depth")
         if width < 1:
@@ -131,7 +132,7 @@ class DEVStoneWrapper(CoupledDEVS, ABC):
             else:
                 atomic = DelayedAtomic("Atomic_0_0", int_delay, ext_delay, add_out_port=True, prep_time=1.0, mode=mode)
 
-            self.addSubModel(atomic)
+            self.models.append(self.addSubModel(atomic))
 
             self.connectPorts(self.i_in, atomic.i_in)
             self.connectPorts(atomic.o_out, self.o_out)
@@ -150,7 +151,26 @@ class DEVStoneWrapper(CoupledDEVS, ABC):
                 else:
                     atomic = DelayedAtomic("Atomic_%d_%d" % (depth - 1, idx), int_delay, ext_delay,
                                            add_out_port=add_atomic_out_ports, prep_time=1.0 + (idx * 1e-6), mode=mode)
-                self.addSubModel(atomic)
+                self.models.append(self.addSubModel(atomic))
+
+    def extend(self, string: str, width: int):
+        length = len(string)
+        return string + " "*(width - length)
+
+    def __str__(self):
+        result = [self.extend(self.name, 16) + "\n", "-" * 20 + "\n"]
+
+        first = self.component_set[0]
+        coupled = ""
+        if isinstance(first, CoupledDEVS):
+            result.append("| " + self.extend(first.name, 16) + " |\n")
+            coupled = "\n\n" + first.__str__()
+
+        for model in self.models:
+            result.append("| " + self.extend(model.name, 16) + " |\n")
+        result.append("-"*20 + "\n")
+        result.append(coupled)
+        return "".join(result)
 
     @abstractmethod
     def gen_coupled(self):
@@ -388,7 +408,7 @@ class dLI(DEVStoneWrapper):
         super().__init__(name, depth, width, int_delay, ext_delay, add_atomic_out_ports=False, prep_time=prep_time,
                          stats=stats, mode="LI-Dynamic")
 
-        self.max_gen = 1
+        self.max_gen = 5
         for idx in range(1, len(self.component_set)):
             assert isinstance(self.component_set[idx], AtomicDEVS)
             self.connectPorts(self.i_in, self.component_set[idx].i_in)
@@ -400,7 +420,8 @@ class dLI(DEVStoneWrapper):
                    prep_time=self.prep_time, stats=self.stats)
 
     def modelTransition(self, state):
-        if state.get("generate", True) and len(self.component_set) > 1:
+        if state.get("generate", True) and self.depth > 1:
+            # print("model", self.name)
             self.connectPorts(self.i_in, self.component_set[0].i_in)
             name = "Atomic_%d_%d" % (self.depth - 1, self.width) if self.depth > 1 else "Atomic_0_%d" % self.width
             if self.stats:
@@ -409,7 +430,8 @@ class dLI(DEVStoneWrapper):
             else:
                 new_atom = DelayedAtomic(name, self.int_delay, self.ext_delay,
                                          add_out_port=self.add_atomic_out_ports, prep_time=self.prep_time, mode="LI-Dynamic")
-            self.addSubModel(new_atom)
+
+            self.models.append(self.addSubModel(new_atom))
             self.connectPorts(self.i_in, new_atom.i_in)
 
             self.width += 1
@@ -426,7 +448,7 @@ class dHI(DEVStoneWrapper):
         super().__init__(name, depth, width, int_delay, ext_delay, add_atomic_out_ports=True, prep_time=prep_time,
                          stats=stats, mode="HI-Dynamic")
 
-        self.max_gen = 10
+        self.max_gen = 5
         if len(self.component_set) > 1:
             assert isinstance(self.component_set[-1], AtomicDEVS)
             self.connectPorts(self.i_in, self.component_set[-1].i_in)
@@ -443,7 +465,7 @@ class dHI(DEVStoneWrapper):
                    prep_time=self.prep_time, stats=self.stats)
 
     def modelTransition(self, state):
-        if state.get("generate", True) and len(self.component_set) > 1:
+        if state.get("generate", True) and self.depth > 1:
             name = "Atomic_%d_%d" % (self.depth - 1, self.width) if self.depth > 1 else "Atomic_0_%d" % self.width
             if self.stats:
                 new_atom = DelayedAtomicStats(name, self.int_delay, self.ext_delay,
@@ -454,10 +476,10 @@ class dHI(DEVStoneWrapper):
 
             last = self.component_set[-2]
 
-            self.addSubModel(new_atom)
+            self.models.append(self.addSubModel(new_atom))
+            self.connectPorts(self.i_in, new_atom.i_in)
             if isinstance(last, AtomicDEVS) and hasattr(last, "o_out"):
                 self.connectPorts(last.o_out, new_atom.i_in)
-            self.connectPorts(self.i_in, new_atom.i_in)
 
             self.width += 1
             # print(f"{self.name}: added {new_atom.name} (width is now {self.width})")