rparedis 3 years ago
parent
commit
41ad32f8da

+ 5 - 5
doc/examples/Dashboard.rst

@@ -71,7 +71,7 @@ needs be.
     canvas.get_tk_widget().grid(column=1, row=1)
 
     manager = PlotManager()
-    manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+    manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
     manager.connect('sin', 'update',
                     lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
     manager.connect('sin', 'update',
@@ -93,16 +93,16 @@ during runtime. Take a look at the corresponding documentations for more informa
     label.grid(column=1, row=2)
 
     def set_amplitude(val):
-        cbd.findBlock("A")[0].setValue(float(val))
+        cbd.find("A")[0].setValue(float(val))
         update_label()
 
     def set_period(val):
-        cbd.findBlock("B")[0].setValue(float(val))
+        cbd.find("B")[0].setValue(float(val))
         update_label()
 
     def update_label():
-        label["text"] = "y = {:.2f} * sin({:.2f} * t)".format(cbd.findBlock("A")[0].getValue(),
-                                                              cbd.findBlock("B")[0].getValue())
+        label["text"] = "y = {:.2f} * sin({:.2f} * t)".format(cbd.find("A")[0].getValue(),
+                                                              cbd.find("B")[0].getValue())
 
     amplitude = tk.Scale(root, label="Amplitude", length=1200, orient=tk.HORIZONTAL, from_=0, to=5,
                          resolution=0.1, command=set_amplitude)

+ 3 - 3
doc/examples/LivePlot.rst

@@ -77,7 +77,7 @@ builtin plotting window.
     plot = fig, ax
 
     manager = PlotManager()
-    manager.register("sin", sinGen.findBlock('collector')[0], plot, LinePlot(color='red'))
+    manager.register("sin", sinGen.find('collector')[0], plot, LinePlot(color='red'))
     manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
     # NOTE: alternatively, manager.set_xlim method can be used:
     #   manager.connect('sin', 'update', lambda d, p=plot: manager.set_xlim(p, follow(d[0], 10.0, lower_bound=0.0)))
@@ -164,7 +164,7 @@ variation.
     canvas.get_tk_widget().grid(column=1, row=1)
 
     manager = PlotManager()
-    manager.register("sin", sinGen.findBlock('collector')[0], (fig, ax), LinePlot(color='red'))
+    manager.register("sin", sinGen.find('collector')[0], (fig, ax), LinePlot(color='red'))
     manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
     sim = Simulator(sinGen)
@@ -215,7 +215,7 @@ this command, plots may start to "flicker" as the updates take too long.
 
     # Use the Bokeh Backend
     manager = PlotManager(Backend.BOKEH)
-    manager.register("sin", sinGen.findBlock('collector')[0], fig, LinePlot(color='red'))
+    manager.register("sin", sinGen.find('collector')[0], fig, LinePlot(color='red'))
     manager.connect('sin', 'update', lambda d:
                         manager.bokeh_set_xlim(fig, document, follow(d[0], 10.0, lower_bound=0.0)))
 

+ 1 - 1
examples/notebook/.ipynb_checkpoints/SinGen-checkpoint.ipynb

@@ -1015,7 +1015,7 @@
     "\n",
     "\n",
     "manager = PlotManager()\n",
-    "manager.register(\"sin\", sinGen.findBlock('collector')[0], (fig, ax), LinePlot(color='red'))\n",
+    "manager.register(\"sin\", sinGen.find('collector')[0], (fig, ax), LinePlot(color='red'))\n",
     "manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))\n",
     "\n",
     "sim = Simulator(sinGen)\n",

+ 1 - 1
examples/notebook/SinGen.ipynb

@@ -1015,7 +1015,7 @@
     "\n",
     "\n",
     "manager = PlotManager()\n",
-    "manager.register(\"sin\", sinGen.findBlock('collector')[0], (fig, ax), LinePlot(color='red'))\n",
+    "manager.register(\"sin\", sinGen.find('collector')[0], (fig, ax), LinePlot(color='red'))\n",
     "manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))\n",
     "\n",
     "sim = Simulator(sinGen)\n",

+ 5 - 5
examples/scripts/Dashboard/SinGen_experiment.py

@@ -19,7 +19,7 @@ canvas.draw()
 canvas.get_tk_widget().grid(column=1, row=1)
 
 manager = PlotManager()
-manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
 manager.connect('sin', 'update',
                 lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 manager.connect('sin', 'update',
@@ -29,16 +29,16 @@ label = tk.Label(root, text="y = 1.00 * sin(1.00 * t)")
 label.grid(column=1, row=2)
 
 def set_amplitude(val):
-	cbd.findBlock("A")[0].setValue(float(val))
+	cbd.find("A")[0].setValue(float(val))
 	update_label()
 
 def set_period(val):
-	cbd.findBlock("B")[0].setValue(float(val))
+	cbd.find("B")[0].setValue(float(val))
 	update_label()
 
 def update_label():
-	label["text"] = "y = {:.2f} * sin({:.2f} * t)".format(cbd.findBlock("A")[0].getValue(),
-	                                                      cbd.findBlock("B")[0].getValue())
+	label["text"] = "y = {:.2f} * sin({:.2f} * t)".format(cbd.find("A")[0].getValue(),
+	                                                      cbd.find("B")[0].getValue())
 
 amplitude = tk.Scale(root, label="Amplitude", length=1200, orient=tk.HORIZONTAL, from_=0, to=5,
                      resolution=0.1, command=set_amplitude)

+ 1 - 1
examples/scripts/LCG2/LCG_experiment.py

@@ -15,7 +15,7 @@ ax.set_ylim((0, 9))
 cbd = LCG("LCG")
 
 manager = PlotManager()
-manager.register("lcg", cbd.findBlock('collector')[0], (fig, ax), ScatterPlot())
+manager.register("lcg", cbd.find('collector')[0], (fig, ax), ScatterPlot())
 manager.connect('lcg', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
 

+ 1 - 1
examples/scripts/LivePlot/SinGen_bokeh_experiment.py

@@ -13,7 +13,7 @@ document.add_root(fig)
 
 # Use the Bokeh Backend
 manager = PlotManager(Backend.BOKEH)
-manager.register("sin", sinGen.findBlock('collector')[0], fig, StepPlot(color='green', line_width=3))
+manager.register("sin", sinGen.find('collector')[0], fig, StepPlot(color='green', line_width=3))
 
 manager.connect('sin', 'update', lambda d:
 					manager.bokeh_set_xlim(fig, document, follow(d[0], 10.0, lower_bound=0.0)))

+ 1 - 1
examples/scripts/LivePlot/SinGen_matplotlib_experiment.py

@@ -11,7 +11,7 @@ ax.set_ylim((-1, 1))    # The sine wave never exceeds this range
 plot = fig, ax
 
 manager = PlotManager()
-manager.register("sin", sinGen.findBlock('collector')[0], plot, LinePlot(color='red'))
+manager.register("sin", sinGen.find('collector')[0], plot, LinePlot(color='red'))
 # manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 manager.connect('sin', 'update', lambda d, p=plot: manager.set_xlim(p, follow(d[0], 10.0, lower_bound=0.0)))
 # NOTE: alternatively, the CBD.realtime.plotting.set_xlim method can be used:

+ 1 - 1
examples/scripts/LivePlot/SinGen_seaborn_experiment.py

@@ -13,7 +13,7 @@ ax = fig.add_subplot(111)
 ax.set_ylim((-1, 1))    # The sine wave never exceeds this range
 
 manager = PlotManager(Backend.SEABORN)
-manager.register("sin", sinGen.findBlock('collector')[0], (fig, ax), LinePlot(color='red'))
+manager.register("sin", sinGen.find('collector')[0], (fig, ax), LinePlot(color='red'))
 manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
 sim = Simulator(sinGen)

+ 1 - 1
examples/scripts/LivePlot/SinGen_tkinter_experiment.py

@@ -20,7 +20,7 @@ canvas.draw()
 canvas.get_tk_widget().grid(column=1, row=1)
 
 manager = PlotManager()
-manager.register("sin", sinGen.findBlock('collector')[0], (fig, ax), LinePlot(color='red'))
+manager.register("sin", sinGen.find('collector')[0], (fig, ax), LinePlot(color='red'))
 manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
 sim = Simulator(sinGen)

+ 3 - 3
experiments/AGV/AGVEnv.py

@@ -123,9 +123,9 @@ class AGVEnv(gym.Env):
 	def get_state(self, model):
 		dd = model.getBlockByName("plot").data
 		if len(dd) == 0:
-			x = model.findBlock("odo.init_x")[0].getValue()
-			y = model.findBlock("odo.init_y")[0].getValue()
-			heading = model.findBlock("odo.init_w")[0].getValue()
+			x = model.find("odo.init_x")[0].getValue()
+			y = model.find("odo.init_y")[0].getValue()
+			heading = model.find("odo.init_w")[0].getValue()
 		else:
 			x, y = model.getBlockByName("plot").data[-1]
 			heading = model.getBlockByName("headingPlot").data_xy[1][-1]

+ 4 - 4
experiments/AGV/AGV_experiment.py

@@ -30,16 +30,16 @@ cbd = AGVVirtual("AGVVirtual", path_file="paths/falcon.csv", initial=[0, -.3, 0]
 # cbd = AGVVirtual("AGVVirtual", initial=[0, -0.3, PI], Kp=Kp, Ki=Ki, Kd=Kd)
 # cbd = Test("Test")
 
-env = cbd.findBlock("environment")[0]
+env = cbd.find("environment")[0]
 path = env.path
 ax1.plot([e[0] for e in path], [e[1] for e in path], color='lightcoral', lw=5, label="environment")
 
-plot = cbd.findBlock("plot")[0]
+plot = cbd.find("plot")[0]
 manager = PlotManager()
 manager.register("plot", plot, (fig, ax1), LinePlot())
 heading = Arrow(0.03, 0.02, color="blue")
-manager.register("heading", cbd.findBlock("headingPlot")[0], (fig, ax1), heading)
-# manager.register("error", cbd.findBlock("errorPlot")[0], (fig, ax2), LinePlot())
+manager.register("heading", cbd.find("headingPlot")[0], (fig, ax1), heading)
+# manager.register("error", cbd.find("errorPlot")[0], (fig, ax2), LinePlot())
 # manager.connect('plot', 'update', lambda d, axis=ax1: axis.set_xlim((min(d[0]), max(d[0]))))
 # manager.connect('plot', 'update', lambda d, axis=ax1: axis.set_ylim((min(d[1]), max(d[1]))))
 # manager.connect('heading', 'update', lambda d, axis=ax2: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))

+ 10 - 10
experiments/AGV/AGV_tuning.py

@@ -36,16 +36,16 @@ for Ki in np.arange(0.0, -0.06, -0.01):
 			                 wheel_radius=0.028, wheel_axis=0.12)
 			# cbd = Test("Test")
 
-			# env = cbd.findBlock("environment")[0]
+			# env = cbd.find("environment")[0]
 			# path = env.path
 			# ax1.plot([e[0] for e in path], [e[1] for e in path], color='lightcoral', linewidth=3, label="environment")
 			#
-			# plot = cbd.findBlock("plot")[0]
+			# plot = cbd.find("plot")[0]
 			# manager = PlotManager()
 			# manager.register("plot", plot, (fig, ax1), LinePlot())
 			# heading = Arrow(0.05, 0.02, color="blue")
-			# manager.register("heading", cbd.findBlock("headingPlot")[0], (fig, ax1), heading)
-			# manager.register("error", cbd.findBlock("errorPlot")[0], (fig, ax2), LinePlot(label="AGV"))
+			# manager.register("heading", cbd.find("headingPlot")[0], (fig, ax1), heading)
+			# manager.register("error", cbd.find("errorPlot")[0], (fig, ax2), LinePlot(label="AGV"))
 			# # manager.connect('plot', 'update', lambda d, axis=ax1: axis.set_xlim((min(d[0]), max(d[0]))))
 			# # manager.connect('plot', 'update', lambda d, axis=ax1: axis.set_ylim((min(d[1]), max(d[1]))))
 			# # manager.connect('heading', 'update', lambda d, axis=ax2: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
@@ -69,9 +69,9 @@ for Ki in np.arange(0.0, -0.06, -0.01):
 			# ax1.legend(loc='best')
 			# plt.show()
 
-			dist = cbd.findBlock("plot")[0].distance_from_start()
+			dist = cbd.find("plot")[0].distance_from_start()
 			if dist > 0:
-				error = cbd.findBlock("errorPlot")[0].data_xy[1][-1] / dist
+				error = cbd.find("errorPlot")[0].data_xy[1][-1] / dist
 			else:
 				error = float('inf')
 
@@ -81,17 +81,17 @@ for Ki in np.arange(0.0, -0.06, -0.01):
 
 			file.write("{}\n".format(txt))
 			file.flush()
-			# print(cbd.findBlock("Controller")[0].getSignalHistory("velocity"))
-			# print(cbd.findBlock("plot")[0].data_xy)
+			# print(cbd.find("Controller")[0].getSignalHistory("velocity"))
+			# print(cbd.find("plot")[0].data_xy)
 
 
 			fig, ax1 = plt.subplots(1, 1)
 			ax1.set_xlim((-0.45, 0.45))
 			ax1.set_ylim((-0.35, 0.55))
 
-			env = cbd.findBlock("environment")[0]
+			env = cbd.find("environment")[0]
 			path = env.path
-			traj = cbd.findBlock("plot")[0]
+			traj = cbd.find("plot")[0]
 			ax1.plot([e[0] for e in path], [e[1] for e in path], color='red', linewidth=3)
 			ax1.plot(*traj.data_xy, color='blue')
 			ax1.set_title(txt)

+ 2 - 2
experiments/AGV/generate_plot.py

@@ -21,7 +21,7 @@ if __name__ == '__main__':
 	model = AGVVirtual("AGV", path_file="paths/falcon.csv", Kp=0.0, Ki=0.0, Kd=-0.02, v=0.001, T=35,
 	                   wheel_radius=0.016512, wheel_axis=0.1944, initial=[0, -.3, 0])
 
-	traj = model.findBlock("environment")[0].path
+	traj = model.find("environment")[0].path
 	ax.plot([x for x, _ in traj], [y for _, y in traj], c='salmon', label="path")
 
 	sets = {
@@ -41,7 +41,7 @@ if __name__ == '__main__':
 	# print(data012)
 
 # manager = PlotManager()
-# manager.register("plot", model.findBlock("plot")[0], (fig, ax), LinePlot())
+# manager.register("plot", model.find("plot")[0], (fig, ax), LinePlot())
 #
 # sim = Simulator(model)
 # sim.setDeltaT(DELTA_T)

+ 10 - 10
experiments/AGV/tracking.py

@@ -166,9 +166,9 @@ class TrackingSimulator:
 	def get_state(self):
 		dd = self.model.getBlockByName("plot").data
 		if len(dd) == 0:
-			x = self.model.findBlock("odo.init_x")[0].getValue()
-			y = self.model.findBlock("odo.init_y")[0].getValue()
-			heading = self.model.findBlock("odo.init_w")[0].getValue()
+			x = self.model.find("odo.init_x")[0].getValue()
+			y = self.model.find("odo.init_y")[0].getValue()
+			heading = self.model.find("odo.init_w")[0].getValue()
 		else:
 			x, y = self.model.getBlockByName("plot").data[-1]
 			heading = self.model.getBlockByName("headingPlot").data_xy[1][-1]
@@ -180,18 +180,18 @@ class TrackingSimulator:
 
 	def set_state(self, state):
 		x, y, heading = state
-		self.model.findBlock("odo.init_x")[0].setValue(x)
-		self.model.findBlock("odo.init_y")[0].setValue(y)
-		self.model.findBlock("odo.init_w")[0].setValue(heading)
+		self.model.find("odo.init_x")[0].setValue(x)
+		self.model.find("odo.init_y")[0].setValue(y)
+		self.model.find("odo.init_w")[0].setValue(heading)
 
 	def get_params(self):
-		d = self.model.findBlock("StaticPlant.WheelAxis")[0].getValue()
-		r = 1. / self.model.findBlock("StaticPlant.WheelRadius")[0].getValue()
+		d = self.model.find("StaticPlant.WheelAxis")[0].getValue()
+		r = 1. / self.model.find("StaticPlant.WheelRadius")[0].getValue()
 		return r, d
 
 	def set_params(self, r, d):
-		self.model.findBlock("StaticPlant.WheelAxis")[0].setValue(d)
-		self.model.findBlock("StaticPlant.WheelRadius")[0].setValue(1./r)
+		self.model.find("StaticPlant.WheelAxis")[0].setValue(d)
+		self.model.find("StaticPlant.WheelRadius")[0].setValue(1. / r)
 
 	def last_good_state(self):
 		if len(self.traces) >= 1:

+ 3 - 3
experiments/LotkeVolterra/diagram_experiment.py

@@ -37,8 +37,8 @@ print(c2l.render())
 # import matplotlib.pyplot as plt
 # fig = plt.figure()
 # ax = fig.add_subplot(111)
-# plot(cbd.findBlock("rabbits")[0], (fig, ax), LinePlot(color='red', label='rabbits'))
-# plot(cbd.findBlock("foxes")[0], (fig, ax), LinePlot(color='blue', label='foxes'))
-# # plot(cbd.findBlock("mySin")[0], (fig, ax), LinePlot(color='red'))
+# plot(cbd.find("rabbits")[0], (fig, ax), LinePlot(color='red', label='rabbits'))
+# plot(cbd.find("foxes")[0], (fig, ax), LinePlot(color='blue', label='foxes'))
+# # plot(cbd.find("mySin")[0], (fig, ax), LinePlot(color='red'))
 # ax.legend()
 # plt.show()

+ 1 - 1
experiments/SinGen/SinGen_experiment.py

@@ -29,7 +29,7 @@ canvas.draw()
 canvas.get_tk_widget().grid(column=1, row=1)
 
 manager = PlotManager()
-manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
 manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
 # plt.show(block=False)

+ 1 - 1
experiments/SinGen/bkh.py

@@ -27,7 +27,7 @@ fig = figure(plot_width=500, plot_height=500, y_range=(-1, 1))
 curdoc().add_root(fig)
 
 manager = PlotManager(Backend.BOKEH)
-manager.register("sin", sinGen.findBlock('collector')[0], fig, LinePlot(color='red'))
+manager.register("sin", sinGen.find('collector')[0], fig, LinePlot(color='red'))
 
 def set_xlim(limits):
 	lower, upper = limits

+ 5 - 5
experiments/SinGen/dashboard.py

@@ -47,7 +47,7 @@ canvas.draw()
 canvas.get_tk_widget().grid(column=1, row=1)
 
 manager = PlotManager()
-manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
 manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 # manager.connect('sin', 'update', lambda d, axis=ax: axis.set_ylim((min(d[1]), max(d[1]))))
 manager.connect('sin', 'update', lambda d, axis=ax: axis.set_ylim(follow(d[1], lower_lim=-1.0, upper_lim=1.0)))
@@ -57,16 +57,16 @@ label = tk.Label(root, text="y = 1.00 * sin(1.00 * t)")
 label.grid(column=1, row=2)
 
 def set_amplitude(val):
-	cbd.findBlock("A")[0].setValue(float(val))
+	cbd.find("A")[0].setValue(float(val))
 	update_label()
 
 def set_period(val):
-	cbd.findBlock("B")[0].setValue(float(val))
+	cbd.find("B")[0].setValue(float(val))
 	update_label()
 
 def update_label():
-	label["text"] = "y = {:.2f} * sin({:.2f} * t)".format(cbd.findBlock("A")[0].getValue(),
-	                                                      cbd.findBlock("B")[0].getValue())
+	label["text"] = "y = {:.2f} * sin({:.2f} * t)".format(cbd.find("A")[0].getValue(),
+	                                                      cbd.find("B")[0].getValue())
 
 amplitude = tk.Scale(root, label="Amplitude", length=1200, orient=tk.HORIZONTAL, from_=0, to=5, resolution=0.1,
                      command=set_amplitude)

+ 1 - 1
experiments/SinGen/mpl.py

@@ -27,7 +27,7 @@ ax = fig.add_subplot(111)
 ax.set_ylim((-1, 1))    # The sine wave never exceeds this range
 
 manager = PlotManager()
-manager.register("sin", sinGen.findBlock('collector')[0], (fig, ax), LinePlot(color='red'))
+manager.register("sin", sinGen.find('collector')[0], (fig, ax), LinePlot(color='red'))
 manager.connect('sin', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
 sim = Simulator(sinGen)

+ 1 - 1
experiments/dummy/myCBD_experiment.py

@@ -14,7 +14,7 @@ ax.set_ylim((-1.1, 1.1))
 cbd = myCBD("myCBD")
 
 manager = PlotManager()
-manager.register("signal", cbd.findBlock('signal')[0], (fig, ax), LinePlot(color='red'))
+manager.register("signal", cbd.find('signal')[0], (fig, ax), LinePlot(color='red'))
 manager.connect('signal', 'update', lambda d, axis=ax: axis.set_xlim(follow(d[0], 15.0, lower_bound=0.0, perc_keep=0.75)))
 
 # Run the Simulation

+ 42 - 21
src/CBD/Core.py

@@ -1,23 +1,27 @@
+import re
+import logging
+from copy import deepcopy
 from .util import enum, hash64
 from collections import namedtuple
-from copy import deepcopy
-import re
-
-from CBD import naivelog
 
 InputLink = namedtuple("InputLink", ["block", "output_port"])
 Signal = namedtuple("Signal", ["time", "value"])
 
+# Error logging
+level = enum(WARNING=1, ERROR=2, CRITICAL=3)
+class LoggingHandler(logging.StreamHandler):
+    def emit(self, record):
+        super().emit(record)
+        if record.levelno >= logging.ERROR:
+            raise SystemExit(1)
 
-level = enum(WARNING=1, ERROR=2, FATAL=3)
-epsilon = 0.001
+logging.basicConfig(handlers=[LoggingHandler()])
 
-class Port:
 
-    class Direction:
-        IN = 0
-        OUT = 1
+epsilon = 0.001
 
+class Port:
+    Direction = enum(IN=0, OUT=1)
     def __init__(self, name, direction, block):
         self.name = name
         self.direction = direction
@@ -49,6 +53,12 @@ class Port:
     def getHistory(self):
         return self.__history
 
+    def getPreviousPortClosure(self):
+        inc = self.getIncoming().source
+        while inc.getIncoming() is not None:
+            inc = inc.getIncoming().source
+        return inc
+
     def count(self):
         return len(self.__history)
 
@@ -97,7 +107,7 @@ class BaseBlock:
         if name != "":
             self.setBlockName(name)
         if re.match(r"[^a-zA-Z0-9_]", self.__block_name):
-            logger = naivelog.getLogger("CBD")
+            logger = logging.getLogger("CBD")
             logger.warning("Block names should only contain alphanumeric characters or underscores.")
 
         # The output signals produced by this block are encoded in a dictionary.
@@ -462,6 +472,11 @@ class CBD(BaseBlock):
             ignore (iter):  Block class names to ignore in the flattening. When :code:`None`,
                             no blocks are ignored. Defaults to :code:`None`.
             psep (str):     The path separator to use. Defaults to :code:`"."`.
+
+        Note:
+            When an empty CBD block is encountered during flattening, this block will be removed from
+            the resulting flattened model. Add it to the :attr:`ignore` iterable to prevent such a
+            removal.
         """
         if ignore is None: ignore = []
 
@@ -475,13 +490,13 @@ class CBD(BaseBlock):
                 for port in block.getInputPorts() + block.getOutputPorts():
                     source = port.getIncoming().source
                     Port.disconnect(source, port)
-                    for conn in port.getOutgoing():
+                    outgoing = port.getOutgoing()[:]
+                    for conn in outgoing:
                         target = conn.target
                         Port.disconnect(port, target)
                         self.addConnection(source.block, target.block, target.name, source.name)
                 self.removeBlock(block)
 
-
     def getBlocks(self):
         """
         Gets the list of blocks.
@@ -574,8 +589,8 @@ class CBD(BaseBlock):
             if isinstance(block, (Clock, DummyClock)):
                 self.__clock = block
         else:
-            logger = naivelog.getLogger("CBD")
-            logger.warning("Warning: did not add this block as it has the same name %s as an already existing block/port" % block.getBlockName())
+            logger = logging.getLogger("CBD")
+            logger.warning("Warning: did not add this block as it has the same name '%s' as an already existing block/port" % block.getBlockName())
 
     def removeBlock(self, block):
         """
@@ -635,8 +650,8 @@ class CBD(BaseBlock):
             block = self.getBlockByName(block)
         block.unlinkInput(input_port_name)
 
-    def findBlock(self, path, sep='.'):
-        """Obtain a block in a submodel of this CBD.
+    def find(self, path, sep='.'):
+        """Obtain a block/port in a submodel of this CBD.
 
         Args:
             path (str): The path of the block to find. Empty string for the current block,
@@ -645,13 +660,13 @@ class CBD(BaseBlock):
             sep (str):  The path separator to use. Defaults to :code:`.`
 
         Returns:
-            The block that corresponds to the given path and the path itself.
+            The block that corresponds to the given path and the path to the block itself.
 
-            .. note::   The block that will be returned has a different path than the path provided
+            .. note::   The block/port that will be returned has a different path than the path provided
                         in this function call. This is because this function assumes you already have
                         a path to the CBD you call it on. For instance, if this CBD contains a child
                         called :code:`child`, which has a :code:`grandchild` block in its turn, calling
-                        findBlock on the :class:`child` to locate the :code:`grandchild` only needs
+                        find on the :class:`child` to locate the :code:`grandchild` only needs
                         :code:`grandchild` to be passed as a path. If the function is called on the
                         current CBD block instead, :code:`child.grandchild` is required to obtain the
                         same block.
@@ -662,6 +677,12 @@ class CBD(BaseBlock):
         for p in path.split(sep):
             if p in cur.__blocksDict:
                 cur = cur.getBlockByName(p)
+            elif p in cur.getInputPortNames():
+                cur = cur.getInputPortByName(p)
+                path = cur.block.getPath()
+            elif p in cur.getOutputPortNames():
+                cur = cur.getOutputPortByName(p)
+                path = cur.block.getPath()
             else:
                 raise ValueError("Cannot find block '{}' in '{}'.".format(p, cur.getPath()))
         return cur, path
@@ -740,7 +761,7 @@ class CBD(BaseBlock):
                             :code:`False`, the identifier will start at 1 and
                             no hashing will be done. Defaults to :code:`False`.
         """
-        names = set([x.getBlockName() for x in self.getBlocks()])
+        names = set([x.getBlockName() for x in self.getBlocks()] + self.getInputPortNames() + self.getOutputPortNames())
         uid = 1
         if hash:
             uid = id(self)

+ 12 - 11
src/CBD/depGraph.py

@@ -148,9 +148,10 @@ class DepGraph:
 				inf_out = inp.getIncoming().source
 				if inf_out.block == influencer:
 					inf = inf_out.getIncoming().source
+					if inf.block == influencer:
+						# Look beyond, because normal connection is straight-through
+						inf = inf.getIncoming().source
 					self.setDependency(dependent, inf.block, curIt)
-			# for output_port in [y.output_port for (x, y) in dependent.getLinksIn().items() if y.block == influencer]:
-			# 	self.setDependency(dependent, influencer.getBlockByName(output_port), curIt)
 			return
 
 		# Link CBD inputs
@@ -160,17 +161,17 @@ class DepGraph:
 			# connection
 			for inp in dependent.getInputPorts():
 				inf_out = inp.getIncoming().source
+				while isinstance(inf_out.block, CBD):
+					inf_out = inf_out.getIncoming().source
 				if inf_out.block == influencer:
 					for conn in inp.getOutgoing():
-						self.setDependency(conn.target.block, influencer, curIt)
-			# directlyConnected = influencer
-			# inputnames = dependent.getInputName(directlyConnected)
-			#
-			# # When one influencer has multiple connections to this CBD, call this function once
-			# for inputname in inputnames:
-			# 	inputtingBlock = dependent.getBlockByName(inputname)
-			# 	thisdep = inputtingBlock
-			# 	self.setDependency(thisdep, influencer, curIt)
+						dep = conn.target
+						if dep.block == dependent:
+							# Look beyond, because normal connection is straight-through
+							for c2 in dep.getOutgoing():
+								self.setDependency(c2.target.block, influencer, curIt)
+						else:
+							self.setDependency(dep.block, influencer, curIt)
 			return
 
 		if self.hasMember(dependent) and self.hasMember(influencer):

+ 4 - 4
src/CBD/lib/std.py

@@ -2,7 +2,6 @@
 This file contains the standard library for CBD building blocks.
 """
 from CBD.Core import BaseBlock, CBD, level
-from CBD import naivelog
 import math
 
 __all__ = ['ConstantBlock', 'NegatorBlock', 'InverterBlock', 'AdderBlock', 'ProductBlock', 'ModuloBlock',
@@ -790,6 +789,7 @@ class DelayBlock(BaseBlock):
 			self.appendToSignal(self.getInputSignal(curIteration - 1).value)
 
 
+import logging
 class LoggingBlock(BaseBlock):
 	"""
 	A simple logging block that logs a string if the input is *truthy*.
@@ -809,7 +809,7 @@ class LoggingBlock(BaseBlock):
 	def __init__(self, block_name, string, lev=level.WARNING, logger="CBDLogger"):
 		BaseBlock.__init__(self, block_name, ["IN1"], [])
 		self.__string = string
-		self.__logger = naivelog.getLogger(logger)
+		self.__logger = logging.getLogger(logger)
 		self.__lev = lev
 
 	def compute(self, curIteration):
@@ -818,8 +818,8 @@ class LoggingBlock(BaseBlock):
 				self.__logger.warning("Time " + str(self.getClock().getTime(curIteration)) + ": " + self.__string)
 			elif self.__lev == level.ERROR:
 				self.__logger.error("Time " + str(self.getClock().getTime(curIteration)) + ": " + self.__string)
-			elif self.__lev == level.FATAL:
-				self.__logger.fatal("Time " + str(self.getClock().getTime(curIteration)) + ": " + self.__string)
+			elif self.__lev == level.CRITICAL:
+				self.__logger.critical("Time " + str(self.getClock().getTime(curIteration)) + ": " + self.__string)
 
 
 class TimeBlock(BaseBlock):

+ 6 - 6
src/CBD/loopsolvers/linearsolver.py

@@ -33,7 +33,7 @@ class LinearSolver(Solver):
 	"""
 	def checkValidity(self, path, component):
 		if not self.__isLinear(component):
-			self._logger.fatal("Cannot solve non-linear algebraic loop.\nSelf: {}\nComponents: {}".format(path, component))
+			self._logger.critical("Cannot solve non-linear algebraic loop.\nSelf: {}\nComponents: {}".format(path, component))
 
 	def __isLinear(self, strongComponent):
 		"""Determines if an algebraic loop describes a linear equation or not.
@@ -70,7 +70,7 @@ class LinearSolver(Solver):
 		for block in strongComponent:
 			# condition (1)
 			if block.getBlockType() == "ProductBlock":
-				dependenciesUnknown = [x for x in block.getDependencies(0) if x in strongComponent]
+				dependenciesUnknown = [x for x in block.getDependencies(0) if x.block in strongComponent]
 				if len(dependenciesUnknown) >= 2:
 					return False
 
@@ -95,16 +95,16 @@ class LinearSolver(Solver):
 		known = {}
 		for block in strongComponent:
 			for inp in block.getInputPorts():
-				fblock = block.getBlockConnectedToInput(inp).block
+				fblock = inp.getPreviousPortClosure().block
+				# fblock = block.getBlockConnectedToInput(inp.name).block
 				if fblock not in strongComponent:
 					val = inp.getHistory()[curIteration].value
-					known[block.getPath(sep) + sep + inp] = val
+					known[block.getPath(sep) + sep + inp.name] = val
 					known[fblock.getPath(sep)] = val
-		print(known)
 		try:
 			return self.get_matrix(strongComponent, sep, known)
 		except ValueError as e:
-			self._logger.fatal(str(e))
+			self._logger.exception(str(e))
 
 	@staticmethod
 	def get_matrix(strongComponent, sep='.', known=None):

+ 2 - 2
src/CBD/loopsolvers/solver.py

@@ -3,7 +3,7 @@ Algebraic loops can be complex to solve.
 This module provides a base class for all loop solvers.
 """
 
-from CBD import naivelog
+import logging
 
 class Solver:
 	"""
@@ -14,7 +14,7 @@ class Solver:
 	"""
 	def __init__(self, logger=None):
 		if logger is None:
-			logger = naivelog.getLogger("CBD")
+			logger = logging.getLogger("CBD")
 		self._logger = logger
 
 	def checkValidity(self, path, component):

+ 1 - 1
src/CBD/naivelog.py

@@ -182,7 +182,7 @@ class Logger:
 			sys.stdout.write(self.formatmsg(level,str(mainstr).format(*args, **kwargs)))
 
 		if level >= self.__crashlevel:
-			exit(1)
+			os._exit(1)
 
 	def setLevel(self, level):
 		"""

+ 4 - 4
src/CBD/preprocessing/rungekutta.py

@@ -98,7 +98,7 @@ class RKPreprocessor:
 			new_model.addConnection("clock-delta", "clock", "h")
 			new_model.addConnection("clock-delta", RK, "h")
 		for itg_name, p in plinks.items():
-			itg = original.findBlock(itg_name)[0]
+			itg = original.find(itg_name)[0]
 			if "IC" in itg.getLinksIn():
 				ic, icop = itg.getBlockConnectedToInput("IC")
 				collection = self.collect(ic, finish=[IntegratorBlock, Clock, TimeBlock])
@@ -505,11 +505,11 @@ if __name__ == '__main__':
 
 	s = model.getSignalHistory("v")
 	L = len(s)
-	errs = model.findBlock("RK.error")[0].getSignalHistory("error")
-	hs = model.findBlock("RK.error")[0].getSignalHistory("h_new")
+	errs = model.find("RK.error")[0].getSignalHistory("error")
+	hs = model.find("RK.error")[0].getSignalHistory("h_new")
 	# errs = hs = s
 
-	# print([x for _, x in model.findBlock("RK.myDelay")[0].getSignalHistory("OUT1")])
+	# print([x for _, x in model.find("RK.myDelay")[0].getSignalHistory("OUT1")])
 
 	import numpy as np
 	print("+------------+------------+------------+------------+------------+------------+")

+ 3 - 3
src/CBD/realtime/plotting.py

@@ -451,7 +451,7 @@ def follow(data, size=None, lower_bound=float('-inf'), upper_bound=float('inf'),
 		.. code-block:: python
 
 			manager = PlotManager()
-			manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+			manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
 			manager.connect('sin', 'update', lambda d, a=ax: a.set_xlim(follow(d[0], 10.0, lower_bound=0.0)))
 
 		- Follow a sine wave in the negative-x direction, always keeping a width of 10, in matplotlib.
@@ -459,7 +459,7 @@ def follow(data, size=None, lower_bound=float('-inf'), upper_bound=float('inf'),
 		.. code-block:: python
 
 			manager = PlotManager()
-			manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+			manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
 			manager.connect('sin', 'update', lambda d, a=ax: a.set_xlim(follow(d[0], 10.0, upper_bound=0.0)))
 
 		- Follow a positive sine-wave, but keep a 10% margin from the right edge of the plot, in matplotlib.
@@ -467,7 +467,7 @@ def follow(data, size=None, lower_bound=float('-inf'), upper_bound=float('inf'),
 		.. code-block:: python
 
 			manager = PlotManager()
-			manager.register("sin", cbd.findBlock("plot")[0], (fig, ax), LinePlot())
+			manager.register("sin", cbd.find("plot")[0], (fig, ax), LinePlot())
 			manager.connect('sin', 'update', lambda d, a=ax: a.set_xlim(follow(d[0], 10.0, 0.0, perc_keep=0.9)))
 	"""
 	if lower_bound >= upper_bound:

+ 1 - 3
src/CBD/simulator.py

@@ -1,7 +1,5 @@
-import sys
 import logging
 import threading
-from CBD import naivelog
 from CBD.depGraph import createDepGraph
 from CBD.loopsolvers.linearsolver import LinearSolver
 from CBD.realtime.threadingBackend import ThreadingBackend, Platform
@@ -100,7 +98,7 @@ class Simulator:
 		self.__progress = False
 		self.__progress_event = None
 		self.__progress_finished = True
-		self.__logger = naivelog.getLogger("CBD")
+		self.__logger = logging.getLogger("CBD")
 		self.__tracer = Tracers(self)
 
 		self.__lasttime = None

+ 1 - 16
src/test/basicCBDTest.py

@@ -156,22 +156,7 @@ class BasicCBDTestCase(unittest.TestCase):
 		self.CBD.addConnection("a2", "p")
 		self.CBD.addConnection("p", "a2")
 		self.CBD.addConnection("c1", "a2")
-		self.assertRaises(SystemExit, self._run, 5)
-
-	def testFlatten(self):
-		self.CBD = CBD("child", [], ["OUT1"])
-		self.CBD.addBlock(AddOneBlock(block_name="add1"))
-		self.CBD.addBlock(TimeBlock("time"))
-		self.CBD.addConnection("time", "add1")
-		self.CBD.addConnection("add1", "OUT1")
-		self.CBD.flatten()
-
-		self.assertEqual(set([x.getBlockName() for x in self.CBD.getBlocks()]),
-		                 {'time', 'add1.OneConstant', 'add1.PlusOne'})
-
-		self._run(NUM_DISCR_TIME_STEPS)
-
-		self.assertEqual(self.CBD.getSignalHistory("OUT1"), [1, 2, 3, 4, 5, 6])
+		self.assertRaises(SystemExit, self._run, NUM_DISCR_TIME_STEPS)
 
 if __name__ == '__main__':  # pragma: no cover
 	# When this module is executed from the command-line, run all its tests

+ 26 - 9
src/test/flattenCBDTest.py

@@ -18,9 +18,27 @@ class FlattenCBDTest(unittest.TestCase):
 		self.sim.run()
 
 	def _getSignal(self, blockname, output_port = None):
-		block = self.CBD.getBlockByName(blockname)
+		if blockname == "":
+			block = self.CBD
+		else:
+			block = self.CBD.getBlockByName(blockname)
 		signal =  block.getSignalHistory(name_output = output_port)
 		return [x.value for x in signal]
+
+	def testFlatten(self):
+		self.CBD.addOutputPort("OUT1")
+		self.CBD.addBlock(AddOneBlock(block_name="add1"))
+		self.CBD.addBlock(TimeBlock("time"))
+		self.CBD.addConnection("time", "add1")
+		self.CBD.addConnection("add1", "OUT1")
+		self.CBD.flatten()
+
+		self.assertEqual(set([x.getBlockName() for x in self.CBD.getBlocks()]),
+		                 {'time', 'add1.OneConstant', 'add1.PlusOne'})
+
+		self._run(5)
+
+		self.assertEqual([s.value for s in self.CBD.getSignalHistory("OUT1")], [1., 2., 3., 4., 5.])
 							
 	def testInterCBD(self):
 		CBDLittle1 = CBD("first_child", output_ports = ["outCBD1"])
@@ -35,7 +53,7 @@ class FlattenCBDTest(unittest.TestCase):
 		
 		self.CBD.flatten()
 		self._run(5)
-		self.assertEqual(self._getSignal("second_child.inCBD2"), [2.0]*5)
+		self.assertEqual(self._getSignal("first_child.c1"), [2.0]*5)
 
 		
 	def testLinearStrongComponentWithMult(self):
@@ -70,8 +88,8 @@ class FlattenCBDTest(unittest.TestCase):
 			
 		self.CBD.flatten()
 		self._run(5)
-		self.assertEqual(self._getSignal("adderCBD.outAdd"), [-0.75]*5)
-		self.assertEqual(self._getSignal("productCBD.outProd"), [-3.75]*5)
+		self.assertEqual(self._getSignal("adderCBD.a"), [-0.75]*5)
+		self.assertEqual(self._getSignal("productCBD.p"), [-3.75]*5)
 		
 	def testLinearStrongComponentWithNeg(self):
 		CBDConstant1 = CBD("constantCBD1", output_ports = ["outConstant1"])
@@ -112,9 +130,9 @@ class FlattenCBDTest(unittest.TestCase):
 		
 		self.CBD.flatten()
 		self._run(5)
-		self.assertEqual(self._getSignal("adder1CBD.outAdd1"), [6.5]*5)
-		self.assertEqual(self._getSignal("adder2CBD.outAdd2"), [1.5]*5)
-		self.assertEqual(self._getSignal("negatorCBD.outNeg"), [-6.5]*5)
+		self.assertEqual(self._getSignal("adder1CBD.a"), [6.5]*5)
+		self.assertEqual(self._getSignal("adder2CBD.a"), [1.5]*5)
+		self.assertEqual(self._getSignal("negatorCBD.n"), [-6.5]*5)
 		
 	def testInterInterCBD(self):
 		"""
@@ -172,10 +190,9 @@ class FlattenCBDTest(unittest.TestCase):
 		CBDLittle2.addConnection("n", "outCBD2")
 		
 		self.CBD.flatten()
-		self._run(5)		
+		self._run(5)
 		self.assertEqual(self._getSignal("first_child.p"), [14.0]*5)
 		self.assertEqual(self._getSignal("first_child.first_child_of_first_child.n"), [-14.0]*5)
-		self.assertEqual(self._getSignal("first_child.in1CBD1"), [2.0]*5)
 		self.assertEqual(self._getSignal("first_child.a"), [-12.0]*5)
 		self.assertEqual(self._getSignal("a2"), [0.0]*5)
 

+ 6 - 5
src/test/hierarchyCBDTest.py

@@ -18,8 +18,8 @@ class HierarchyCBDTest(unittest.TestCase):
 		self.sim.run()
 
 	def _getSignal(self, blockname, output_port = None):
-		block = self.CBD.getBlockByName(blockname)
-		signal =  block.getSignalHistory(name_output = output_port)
+		block = self.CBD.find(blockname)[0]
+		signal = block.getSignalHistory(name_output = output_port)
 		return [x.value for x in signal]
 		
 	def testInterCBD(self):		
@@ -175,9 +175,10 @@ class HierarchyCBDTest(unittest.TestCase):
 		CBDLittle2.addConnection("n", "outCBD2")
 		
 		self._run(5)		
-		self.assertEqual(self._getSignal("first_child", output_port = "p"), [14.0]*5)
-		self.assertEqual(self._getSignal("first_child", output_port = "in1CBD1"), [2.0]*5)
-		self.assertEqual(self._getSignal("first_child", output_port = "a"), [-12.0]*5)
+		self.assertEqual(self._getSignal("first_child.p"), [14.0]*5)
+		ih = self.CBD.getBlockByName("first_child").getInputPortByName("in1CBD1").getHistory()
+		self.assertEqual([x.value for x in ih], [2.0]*5)
+		self.assertEqual(self._getSignal("first_child.a"), [-12.0]*5)
 		self.assertEqual(self._getSignal("a2"), [0.0]*5)
 
 if __name__ == '__main__':  # pragma: no cover

+ 1 - 1
src/test/stdCBDTest.py

@@ -456,7 +456,7 @@ class StdCBDTestCase(unittest.TestCase):
 
 	def testLoggingBlockFatal(self):
 		self.CBD.addBlock(ConstantBlock(block_name="One", value=1))
-		self.CBD.addBlock(LoggingBlock("L1", "Logging block test were level is fatal", level.FATAL))
+		self.CBD.addBlock(LoggingBlock("L1", "Logging block test were level is fatal", level.CRITICAL))
 		self.CBD.addConnection("One", "L1")
 		self.assertRaises(SystemExit, self._run, 1)