rparedis 4 år sedan
förälder
incheckning
307493ca16

+ 21 - 9
examples/notebook/.ipynb_checkpoints/HybridTrain-checkpoint.ipynb

@@ -413,18 +413,29 @@
    "source": [
     "from pypdevs.DEVS import CoupledDEVS\n",
     "from CBD.converters.hybrid import CBDRunner\n",
+    "# from CBD.preprocessing.butcher import ButcherTableau as BT\n",
+    "# from CBD.preprocessing.rungekutta import RKPreprocessor\n",
+    "\n",
+    "# RKP = RKPreprocessor(BT.RKF45(), atol=2e-5, hmin=0.1, safety=.84)\n",
     "\n",
     "class TrainModel(CoupledDEVS):\n",
     "    def __init__(self, name, x0, v0, v_min, v_max, stopping_x, max_passengers, dt=0.1):\n",
     "        super().__init__(name)\n",
     "        \n",
-    "        self.accODE = self.addSubModel(CBDRunner(\"accODE\", AcceleratingODE(\"accODE\", dt), {\n",
+    "#         acc = RKP.preprocess(AcceleratingODE(\"accODE\", dt))\n",
+    "#         frc = RKP.preprocess(FrictionODE(\"fricODE\", dt))\n",
+    "#         brk = RKP.preprocess(BrakingODE(\"brakeODE\", dt))\n",
+    "        acc = AcceleratingODE(\"accODE\", dt)\n",
+    "        frc = FrictionODE(\"fricODE\", dt)\n",
+    "        brk = BrakingODE(\"brakeODE\", dt)\n",
+    "        \n",
+    "        self.accODE = self.addSubModel(CBDRunner(\"accODE\", acc, {\n",
     "            'x0': x0, 'v0': v0, 'k': 0.15\n",
     "        }, True, {\"v\": v_max, \"x\": stopping_x}))\n",
-    "        self.fricODE = self.addSubModel(CBDRunner(\"fricODE\", FrictionODE(\"fricODE\", dt), {\n",
+    "        self.fricODE = self.addSubModel(CBDRunner(\"fricODE\", frc, {\n",
     "            'x0': x0, 'v0': v0, 'k': 0.03\n",
     "        }, True, {\"v\": v_min, \"x\": stopping_x}))\n",
-    "        self.brakeODE = self.addSubModel(CBDRunner(\"brakeODE\", BrakingODE(\"brakeODE\", dt), {\n",
+    "        self.brakeODE = self.addSubModel(CBDRunner(\"brakeODE\", brk, {\n",
     "            'x0': x0, 'v0': v0, 'k': 0.08\n",
     "        }, True, {\"v\": 1e-1}))\n",
     "        self.driver = self.addSubModel(Driver(\"driver\", x0, v0, stopping_x, max_passengers))\n",
@@ -1438,7 +1449,7 @@
    "source": [
     "%matplotlib notebook\n",
     "\n",
-    "from CBD.realtime.plotting import PlotManager, LinePlot, StepPlot\n",
+    "from CBD.realtime.plotting import PlotManager, LinePlot, StepPlot, ScatterPlot\n",
     "from pypdevs.simulator import Simulator\n",
     "import matplotlib.pyplot as plt\n",
     "import numpy as np\n",
@@ -1484,17 +1495,18 @@
     "sim.setTerminationTime(XLIM[1])\n",
     "\n",
     "manager = PlotManager()\n",
-    "manager.register(\"vel\", train.plotter, (fig, ax), LinePlot(c='red'))\n",
+    "manager.register(\"vel\", train.plotter, (fig, ax), ScatterPlot(s=2, c='red'))\n",
     "manager.register(\"ppl\", train.hold, (fig, ax2), StepPlot(c='dodgerblue', where='post', ls='-.'))\n",
     "manager.get(\"vel\").set_data_getter(lambda obj: obj.data_v)\n",
     "manager.get(\"ppl\").set_data_getter(lambda obj: ([x for x, _ in obj.state[\"trace\"]], [y for _, y in obj.state[\"trace\"]]))\n",
     "\n",
+    "def term():\n",
+    "    train.plotter.state[\"xs\"].append((XLIM[1], train.plotter.state[\"xs\"][-1][1]))\n",
+    "    train.plotter.state[\"vs\"].append((XLIM[1], 0.0))\n",
+    "    train.hold.state[\"trace\"].append((XLIM[1], 0))\n",
+    "    \n",
     "sim.simulate()\n",
     "\n",
-    "train.plotter.state[\"xs\"].append((XLIM[1], train.plotter.state[\"xs\"][-1][1]))\n",
-    "train.plotter.state[\"vs\"].append((XLIM[1], 0.0))\n",
-    "train.hold.state[\"trace\"].append((XLIM[1], 0))\n",
-    "\n",
     "plt.show()"
    ]
   },

+ 21 - 9
examples/notebook/HybridTrain.ipynb

@@ -413,18 +413,29 @@
    "source": [
     "from pypdevs.DEVS import CoupledDEVS\n",
     "from CBD.converters.hybrid import CBDRunner\n",
+    "# from CBD.preprocessing.butcher import ButcherTableau as BT\n",
+    "# from CBD.preprocessing.rungekutta import RKPreprocessor\n",
+    "\n",
+    "# RKP = RKPreprocessor(BT.RKF45(), atol=2e-5, hmin=0.1, safety=.84)\n",
     "\n",
     "class TrainModel(CoupledDEVS):\n",
     "    def __init__(self, name, x0, v0, v_min, v_max, stopping_x, max_passengers, dt=0.1):\n",
     "        super().__init__(name)\n",
     "        \n",
-    "        self.accODE = self.addSubModel(CBDRunner(\"accODE\", AcceleratingODE(\"accODE\", dt), {\n",
+    "#         acc = RKP.preprocess(AcceleratingODE(\"accODE\", dt))\n",
+    "#         frc = RKP.preprocess(FrictionODE(\"fricODE\", dt))\n",
+    "#         brk = RKP.preprocess(BrakingODE(\"brakeODE\", dt))\n",
+    "        acc = AcceleratingODE(\"accODE\", dt)\n",
+    "        frc = FrictionODE(\"fricODE\", dt)\n",
+    "        brk = BrakingODE(\"brakeODE\", dt)\n",
+    "        \n",
+    "        self.accODE = self.addSubModel(CBDRunner(\"accODE\", acc, {\n",
     "            'x0': x0, 'v0': v0, 'k': 0.15\n",
     "        }, True, {\"v\": v_max, \"x\": stopping_x}))\n",
-    "        self.fricODE = self.addSubModel(CBDRunner(\"fricODE\", FrictionODE(\"fricODE\", dt), {\n",
+    "        self.fricODE = self.addSubModel(CBDRunner(\"fricODE\", frc, {\n",
     "            'x0': x0, 'v0': v0, 'k': 0.03\n",
     "        }, True, {\"v\": v_min, \"x\": stopping_x}))\n",
-    "        self.brakeODE = self.addSubModel(CBDRunner(\"brakeODE\", BrakingODE(\"brakeODE\", dt), {\n",
+    "        self.brakeODE = self.addSubModel(CBDRunner(\"brakeODE\", brk, {\n",
     "            'x0': x0, 'v0': v0, 'k': 0.08\n",
     "        }, True, {\"v\": 1e-1}))\n",
     "        self.driver = self.addSubModel(Driver(\"driver\", x0, v0, stopping_x, max_passengers))\n",
@@ -1438,7 +1449,7 @@
    "source": [
     "%matplotlib notebook\n",
     "\n",
-    "from CBD.realtime.plotting import PlotManager, LinePlot, StepPlot\n",
+    "from CBD.realtime.plotting import PlotManager, LinePlot, StepPlot, ScatterPlot\n",
     "from pypdevs.simulator import Simulator\n",
     "import matplotlib.pyplot as plt\n",
     "import numpy as np\n",
@@ -1484,17 +1495,18 @@
     "sim.setTerminationTime(XLIM[1])\n",
     "\n",
     "manager = PlotManager()\n",
-    "manager.register(\"vel\", train.plotter, (fig, ax), LinePlot(c='red'))\n",
+    "manager.register(\"vel\", train.plotter, (fig, ax), ScatterPlot(s=2, c='red'))\n",
     "manager.register(\"ppl\", train.hold, (fig, ax2), StepPlot(c='dodgerblue', where='post', ls='-.'))\n",
     "manager.get(\"vel\").set_data_getter(lambda obj: obj.data_v)\n",
     "manager.get(\"ppl\").set_data_getter(lambda obj: ([x for x, _ in obj.state[\"trace\"]], [y for _, y in obj.state[\"trace\"]]))\n",
     "\n",
+    "def term():\n",
+    "    train.plotter.state[\"xs\"].append((XLIM[1], train.plotter.state[\"xs\"][-1][1]))\n",
+    "    train.plotter.state[\"vs\"].append((XLIM[1], 0.0))\n",
+    "    train.hold.state[\"trace\"].append((XLIM[1], 0))\n",
+    "    \n",
     "sim.simulate()\n",
     "\n",
-    "train.plotter.state[\"xs\"].append((XLIM[1], train.plotter.state[\"xs\"][-1][1]))\n",
-    "train.plotter.state[\"vs\"].append((XLIM[1], 0.0))\n",
-    "train.hold.state[\"trace\"].append((XLIM[1], 0))\n",
-    "\n",
     "plt.show()"
    ]
   },

+ 71 - 0
examples/notebook/accODE.dot

@@ -0,0 +1,71 @@
+// CBD model of the accODE block
+// Created with CBD.converters.CBDDraw
+digraph model {
+ splines=ortho;
+ label=<<B>accODE (AcceleratingODE)</B>>;
+ labelloc="t";
+ fontsize=20;
+ node_140564513045952 [label="v", shape=none];
+ inter_140564513588464_OUT1 -> node_140564513045952 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_140564513044704 [label="x", shape=none];
+ inter_140564513139872_OUT1 -> node_140564513044704 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_140564513045424 [label=" ConstantBlock\n(five)\n5", shape=ellipse];
+ inter_140564513045424_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513045424 -> inter_140564513045424_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513046048 [label="NegatorBlock\n(neg)", shape=box];
+ inter_140564513063744_OUT1 -> node_140564513046048 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513046048_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513046048 -> inter_140564513046048_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513311664 [label="AdderBlock\n(sum)", shape=box];
+ inter_140564513045424_OUT1 -> node_140564513311664 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513046048_OUT1 -> node_140564513311664 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513588464_OUT1 -> node_140564513311664 [headlabel="IN3", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513311664_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513311664 -> inter_140564513311664_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512923456 [label="ProductBlock\n(mult)", shape=box];
+ inter_140564513311664_OUT1 -> node_140564512923456 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512889680_OUT1 -> node_140564512923456 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512923456_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512923456 -> inter_140564512923456_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513588464 [label="IntegratorBlock\n(Iv)", shape=Msquare];
+ inter_140564512923456_OUT1 -> node_140564513588464 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513063744_OUT1 -> node_140564513588464 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512786896_delta -> node_140564513588464 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513588464_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513588464 -> inter_140564513588464_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513139872 [label="IntegratorBlock\n(Ix)", shape=Msquare];
+ inter_140564513588464_OUT1 -> node_140564513139872 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512930544_OUT1 -> node_140564513139872 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512786896_delta -> node_140564513139872 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513139872_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513139872 -> inter_140564513139872_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512786896 [label="Clock\n(clock-clock)", shape=Msquare];
+ inter_140564512447504_OUT1 -> node_140564512786896 [headlabel="h", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512786896_time [shape=point, width=0.01, height=0.01];
+ node_140564512786896 -> inter_140564512786896_time [taillabel="time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_140564512786896_rel_time [shape=point, width=0.01, height=0.01];
+ node_140564512786896 -> inter_140564512786896_rel_time [taillabel="rel_time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_140564512786896_delta [shape=point, width=0.01, height=0.01];
+ node_140564512786896 -> inter_140564512786896_delta [taillabel="delta", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513065664 [label=" ConstantBlock\n(clock-delta)\n1", shape=ellipse];
+ inter_140564513065664_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513065664 -> inter_140564513065664_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512930544 [label=" ConstantBlock\n(x0)\n0", shape=ellipse];
+ inter_140564512930544_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512930544 -> inter_140564512930544_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513063744 [label=" ConstantBlock\n(v0)\n0.0", shape=ellipse];
+ inter_140564513063744_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513063744 -> inter_140564513063744_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512889680 [label=" ConstantBlock\n(k)\n0.15", shape=ellipse];
+ inter_140564512889680_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512889680 -> inter_140564512889680_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513331232 [label=" ConstantBlock\n(H)\ninf", shape=ellipse];
+ inter_140564513331232_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513331232 -> inter_140564513331232_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512447504 [label="MinBlock\n(Min)", shape=box];
+ inter_140564513331232_OUT1 -> node_140564512447504 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513065664_OUT1 -> node_140564512447504 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512447504_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512447504 -> inter_140564512447504_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+
+}

+ 70 - 0
examples/notebook/brakeODE.dot

@@ -0,0 +1,70 @@
+// CBD model of the brakeODE block
+// Created with CBD.converters.CBDDraw
+digraph model {
+ splines=ortho;
+ label=<<B>brakeODE (BrakingODE)</B>>;
+ labelloc="t";
+ fontsize=20;
+ node_140564513051936 [label="v", shape=none];
+ inter_140564513065328_OUT1 -> node_140564513051936 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_140564513066480 [label="x", shape=none];
+ inter_140564513012368_OUT1 -> node_140564513066480 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_140564513064848 [label=" ConstantBlock\n(three)\n0", shape=ellipse];
+ inter_140564513064848_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513064848 -> inter_140564513064848_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513064512 [label="NegatorBlock\n(neg)", shape=box];
+ inter_140564513254944_OUT1 -> node_140564513064512 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513064512_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513064512 -> inter_140564513064512_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513066960 [label="AdderBlock\n(sum)", shape=box];
+ inter_140564513064848_OUT1 -> node_140564513066960 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513065328_OUT1 -> node_140564513066960 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513066960_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513066960 -> inter_140564513066960_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513115440 [label="ProductBlock\n(mult)", shape=box];
+ inter_140564513066960_OUT1 -> node_140564513115440 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513064512_OUT1 -> node_140564513115440 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513115440_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513115440 -> inter_140564513115440_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513065328 [label="IntegratorBlock\n(Iv)", shape=Msquare];
+ inter_140564513115440_OUT1 -> node_140564513065328 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512840624_OUT1 -> node_140564513065328 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512585376_delta -> node_140564513065328 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513065328_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513065328 -> inter_140564513065328_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513012368 [label="IntegratorBlock\n(Ix)", shape=Msquare];
+ inter_140564513065328_OUT1 -> node_140564513012368 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513397152_OUT1 -> node_140564513012368 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512585376_delta -> node_140564513012368 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513012368_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513012368 -> inter_140564513012368_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512585376 [label="Clock\n(clock-clock)", shape=Msquare];
+ inter_140564512837744_OUT1 -> node_140564512585376 [headlabel="h", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512585376_time [shape=point, width=0.01, height=0.01];
+ node_140564512585376 -> inter_140564512585376_time [taillabel="time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_140564512585376_rel_time [shape=point, width=0.01, height=0.01];
+ node_140564512585376 -> inter_140564512585376_rel_time [taillabel="rel_time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_140564512585376_delta [shape=point, width=0.01, height=0.01];
+ node_140564512585376 -> inter_140564512585376_delta [taillabel="delta", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512912096 [label=" ConstantBlock\n(clock-delta)\n1", shape=ellipse];
+ inter_140564512912096_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512912096 -> inter_140564512912096_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513397152 [label=" ConstantBlock\n(x0)\n0", shape=ellipse];
+ inter_140564513397152_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513397152 -> inter_140564513397152_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512840624 [label=" ConstantBlock\n(v0)\n0.0", shape=ellipse];
+ inter_140564512840624_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512840624 -> inter_140564512840624_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513254944 [label=" ConstantBlock\n(k)\n0.08", shape=ellipse];
+ inter_140564513254944_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513254944 -> inter_140564513254944_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513065568 [label=" ConstantBlock\n(H)\ninf", shape=ellipse];
+ inter_140564513065568_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513065568 -> inter_140564513065568_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512837744 [label="MinBlock\n(Min)", shape=box];
+ inter_140564513065568_OUT1 -> node_140564512837744 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512912096_OUT1 -> node_140564512837744 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512837744_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512837744 -> inter_140564512837744_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+
+}

+ 70 - 0
examples/notebook/fricODE.dot

@@ -0,0 +1,70 @@
+// CBD model of the fricODE block
+// Created with CBD.converters.CBDDraw
+digraph model {
+ splines=ortho;
+ label=<<B>fricODE (FrictionODE)</B>>;
+ labelloc="t";
+ fontsize=20;
+ node_140564548331744 [label="v", shape=none];
+ inter_140564513729408_OUT1 -> node_140564548331744 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_140564512423072 [label="x", shape=none];
+ inter_140564513113280_OUT1 -> node_140564512423072 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_140564512423600 [label=" ConstantBlock\n(m20)\n-30", shape=ellipse];
+ inter_140564512423600_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512423600 -> inter_140564512423600_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512421536 [label="NegatorBlock\n(neg)", shape=box];
+ inter_140564512447744_OUT1 -> node_140564512421536 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512421536_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512421536 -> inter_140564512421536_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513388336 [label="AdderBlock\n(sum)", shape=box];
+ inter_140564512423600_OUT1 -> node_140564513388336 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513729408_OUT1 -> node_140564513388336 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513388336_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513388336 -> inter_140564513388336_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512421632 [label="ProductBlock\n(mult)", shape=box];
+ inter_140564513388336_OUT1 -> node_140564512421632 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512421536_OUT1 -> node_140564512421632 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512421632_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512421632 -> inter_140564512421632_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513729408 [label="IntegratorBlock\n(Iv)", shape=Msquare];
+ inter_140564512421632_OUT1 -> node_140564513729408 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512445008_OUT1 -> node_140564513729408 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513617760_delta -> node_140564513729408 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513729408_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513729408 -> inter_140564513729408_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513113280 [label="IntegratorBlock\n(Ix)", shape=Msquare];
+ inter_140564513729408_OUT1 -> node_140564513113280 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513115344_OUT1 -> node_140564513113280 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513617760_delta -> node_140564513113280 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513113280_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513113280 -> inter_140564513113280_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513617760 [label="Clock\n(clock-clock)", shape=Msquare];
+ inter_140564512445200_OUT1 -> node_140564513617760 [headlabel="h", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564513617760_time [shape=point, width=0.01, height=0.01];
+ node_140564513617760 -> inter_140564513617760_time [taillabel="time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_140564513617760_rel_time [shape=point, width=0.01, height=0.01];
+ node_140564513617760 -> inter_140564513617760_rel_time [taillabel="rel_time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_140564513617760_delta [shape=point, width=0.01, height=0.01];
+ node_140564513617760 -> inter_140564513617760_delta [taillabel="delta", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512924336 [label=" ConstantBlock\n(clock-delta)\n1", shape=ellipse];
+ inter_140564512924336_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512924336 -> inter_140564512924336_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564513115344 [label=" ConstantBlock\n(x0)\n0", shape=ellipse];
+ inter_140564513115344_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564513115344 -> inter_140564513115344_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512445008 [label=" ConstantBlock\n(v0)\n0.0", shape=ellipse];
+ inter_140564512445008_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512445008 -> inter_140564512445008_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512447744 [label=" ConstantBlock\n(k)\n0.03", shape=ellipse];
+ inter_140564512447744_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512447744 -> inter_140564512447744_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512915120 [label=" ConstantBlock\n(H)\ninf", shape=ellipse];
+ inter_140564512915120_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512915120 -> inter_140564512915120_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_140564512445200 [label="MinBlock\n(Min)", shape=box];
+ inter_140564512915120_OUT1 -> node_140564512445200 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512924336_OUT1 -> node_140564512445200 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_140564512445200_OUT1 [shape=point, width=0.01, height=0.01];
+ node_140564512445200 -> inter_140564512445200_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+
+}

+ 70 - 0
examples/notebook/test.dot

@@ -0,0 +1,70 @@
+// CBD model of the brakeODE block
+// Created with CBD.converters.CBDDraw
+digraph model {
+ splines=ortho;
+ label=<<B>brakeODE (BrakingODE)</B>>;
+ labelloc="t";
+ fontsize=20;
+ node_139722717211280 [label="v", shape=none];
+ inter_139722721795088_OUT1 -> node_139722717211280 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_139722717210080 [label="x", shape=none];
+ inter_139722722328832_OUT1 -> node_139722717210080 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_139722721792976 [label=" ConstantBlock\n(three)\n0", shape=ellipse];
+ inter_139722721792976_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722721792976 -> inter_139722721792976_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722721998064 [label="NegatorBlock\n(neg)", shape=box];
+ inter_139722715755856_OUT1 -> node_139722721998064 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722721998064_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722721998064 -> inter_139722721998064_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722719769504 [label="AdderBlock\n(sum)", shape=box];
+ inter_139722721792976_OUT1 -> node_139722719769504 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722721795088_OUT1 -> node_139722719769504 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722719769504_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722719769504 -> inter_139722719769504_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722718093376 [label="ProductBlock\n(mult)", shape=box];
+ inter_139722719769504_OUT1 -> node_139722718093376 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722721998064_OUT1 -> node_139722718093376 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722718093376_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722718093376 -> inter_139722718093376_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722721795088 [label="IntegratorBlock\n(Iv)", shape=Msquare];
+ inter_139722718093376_OUT1 -> node_139722721795088 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722717506192_OUT1 -> node_139722721795088 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722720068896_delta -> node_139722721795088 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722721795088_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722721795088 -> inter_139722721795088_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722722328832 [label="IntegratorBlock\n(Ix)", shape=Msquare];
+ inter_139722721795088_OUT1 -> node_139722722328832 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722716333248_OUT1 -> node_139722722328832 [headlabel="IC", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722720068896_delta -> node_139722722328832 [headlabel="delta_t", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722722328832_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722722328832 -> inter_139722722328832_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722720068896 [label="Clock\n(clock-clock)", shape=Msquare];
+ inter_139722715512256_OUT1 -> node_139722720068896 [headlabel="h", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722720068896_time [shape=point, width=0.01, height=0.01];
+ node_139722720068896 -> inter_139722720068896_time [taillabel="time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_139722720068896_rel_time [shape=point, width=0.01, height=0.01];
+ node_139722720068896 -> inter_139722720068896_rel_time [taillabel="rel_time", arrowtail="invempty", arrowhead="none", dir=both];
+ inter_139722720068896_delta [shape=point, width=0.01, height=0.01];
+ node_139722720068896 -> inter_139722720068896_delta [taillabel="delta", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722717505088 [label=" ConstantBlock\n(clock-delta)\n0.1", shape=ellipse];
+ inter_139722717505088_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722717505088 -> inter_139722717505088_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722716333248 [label=" ConstantBlock\n(x0)\n0", shape=ellipse];
+ inter_139722716333248_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722716333248 -> inter_139722716333248_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722717506192 [label=" ConstantBlock\n(v0)\n0.0", shape=ellipse];
+ inter_139722717506192_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722717506192 -> inter_139722717506192_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722715755856 [label=" ConstantBlock\n(k)\n0.08", shape=ellipse];
+ inter_139722715755856_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722715755856 -> inter_139722715755856_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722714660976 [label=" ConstantBlock\n(H)\ninf", shape=ellipse];
+ inter_139722714660976_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722714660976 -> inter_139722714660976_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139722715512256 [label="MinBlock\n(Min)", shape=box];
+ inter_139722714660976_OUT1 -> node_139722715512256 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722717505088_OUT1 -> node_139722715512256 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139722715512256_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139722715512256 -> inter_139722715512256_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+
+}

+ 175 - 79
src/CBD/converters/hybrid.py

@@ -15,6 +15,156 @@ from copy import deepcopy
 
 __all__ = ['CBDRunner', 'prepare_cbd', 'CrossingDetection']
 
+import math
+class CrossingDetection:
+	"""
+	Helper class that implements the crossing detection algorithms.
+
+	The following description concerns the default arguments for all functions.
+	On top of that, there may be some additional arguments defined, as listed in
+	the specific documentations below.
+
+	Args:
+		t1 (float):     The x-value of the lower bound of the interval.
+		t2 (float):     The x-value of the higher bound of the interval.
+		y (float):      The value for which a crossing must be checked.
+		f:              A function that should return the y-value for a given x (or t).
+	"""
+	@staticmethod
+	def linear(t1, t2, y, f, **kwargs):
+		"""
+		Finds the root of the crossing using linear interpolation.
+		No additional function calls or arguments are used.
+		"""
+		y1 = f(t1)
+		y2 = f(t2)
+		if y1 == y2:
+			return y1
+		return (t2 - t1) / (y2 - y1) * (y - y1) + t1
+
+	@staticmethod
+	def regula_falsi(t1, t2, y, f, **kwargs):
+		"""
+		Implements the Illinois algorithm for finding the root for a crossing problem.
+
+		Args:
+			eps (float):    Half of the upper bound for the relative error.
+							Defaults to 1e-5.
+			n (int):        The maximal amount of iterations to compute. Defaults to
+							5 million iterations.
+
+		See Also:
+			https://en.wikipedia.org/wiki/Regula_falsi
+		"""
+		eps = kwargs.get("eps", 1e-5)
+		n = kwargs.get("n", 5 * 1000 * 1000)
+		y1 = f(t1) - y
+		y2 = f(t2) - y
+		assert y1 * y2 < 0, "No crossing possible in given range"
+		tn, yn = t1, y1
+		side = 0
+		for i in range(n):
+			if abs(t1 - t2) < eps * abs(t1 + t2): break
+			tn = (y1 * t2 - y2 * t1) / (y1 - y2)
+			yn = f(tn) - y
+			if yn * y2 > 0:
+				t2, y2 = tn, yn
+				if side == -1:
+					y1 /= 2
+				side = -1
+			elif yn * y1 > 0:
+				t1, y1 = tn, yn
+				if side == 1:
+					y2 /= 2
+				side = 1
+			else:
+				break
+		return tn
+
+	@staticmethod
+	def ITP(t1, t2, y, f, **kwargs):
+		r"""Implements the Interpolation-Truncation-Projection algorithm for finding
+		the root of a function.
+
+		Args:
+			eps (float):    Minimal interval size. Defaults to 1e-5.
+			k1 (float):     First truncation size hyperparameter. Must be in the
+							range of :math:`(0, \infty)`. Defaults to 0.1.
+			k2 (float):     Second truncation size hyperparameter. Must be in the
+							range of :math:`[1, 1 + \frac{1}{2}(1 + \sqrt{5})]`.
+							Defaults to 1.5.
+			n0 (float):     Slack variable to control the size of the interval for
+							the projection step. Must be in :math:`[0, \infty)`.
+							When 0, the average number of iterations will be less
+							than that of the bisection method. Defaults to 0.
+
+		See Also:
+			https://en.wikipedia.org/wiki/ITP_method
+		"""
+		k1 = kwargs.get("k1", 0.1)
+		k2 = kwargs.get("k2", 1.5)
+		eps = kwargs.get("eps", 1e-5)
+		n0 = kwargs.get("n0", 0)
+
+		assert 0 < k1, "For ITP, k1 must be strictly positive."
+		assert 1 <= k2 <= (1 + (1. + 5 ** 0.5) / 2.), "For ITP, k2 must be in [1, 1 + phi]."
+		assert 0 <= n0, "For ITP, n0 must be positive or zero."
+
+		sign = lambda x: 1 if x > 0 else (-1 if x < 0 else 0)
+
+		a = t1
+		b = t2
+		ya = f(a) - y
+		yb = f(b) - y
+
+		if ya == 0:
+			return a
+		if yb == 0:
+			return b
+		assert ya * yb < 0, "No crossing possible in given range"
+
+		# Preprocessing
+		nh = math.ceil(math.log2((b - a) / (2 * eps)))
+		nm = nh + n0
+		j = 0
+
+		while (b - a) > (2 * eps):
+			xh = (a + b) / 2
+			r = eps * 2 ** (nm - j) - (b - a) / 2
+			d = k1 * (b - a) ** k2
+
+			# Interpolation
+			xf = (yb * a - ya * b) / (yb - ya)
+
+			# Truncation
+			s = sign(xh - xf)
+			if d <= abs(xh - xf):
+				xt = xf + s * d
+			else:
+				xt = xh
+
+			# Projection
+			if abs(xt - xh) <= r:
+				xI = xt
+			else:
+				xI = xh - s * r
+
+			# Update Interval
+			yI = f(xI) - y
+			if (ya - yb) * yI < 0:
+				b = xI
+				yb = yI
+			elif (ya - yb) * yI > 0:
+				a = xI
+				ya = yI
+			else:
+				a = xI
+				b = xI
+			j += 1
+
+		return (a + b) / 2
+
+from CBD.converters.CBDDraw import draw
 class CBDRunner(AtomicDEVS):
 	"""
 	Atomic DEVS model that can be used to execute a CBD model.
@@ -27,12 +177,18 @@ class CBDRunner(AtomicDEVS):
 							In this paused mode, the model will not
 							progress. Useful when in combination with
 							multiple ODEs. Defaults to :code:`False`.
+		algo:               The root finding algorithm function. See
+							:class:`CrossingDetection` for more info.
+		**kwargs:           Optional parameters for the zero-crossing
+							detection algorithm.
 	"""
-	def __init__(self, name, cbd, initials=None, stopped=False, crossings=None):
+	def __init__(self, name, cbd, initials=None, stopped=False, crossings=None, algo=CrossingDetection.ITP, **kwargs):
 		AtomicDEVS.__init__(self, name)
 		self.initials = {} if initials is None else initials
 		self.original_model, self.Hname = prepare_cbd(cbd.clone(), initials)
 		self.crossings = {} if crossings is None else crossings
+		self.algo = algo
+		self.kwargs = kwargs
 
 		self.state = {
 			"CBD": None,
@@ -43,12 +199,12 @@ class CBDRunner(AtomicDEVS):
 			"request_compute": True,
 			"zero_crossing": None,
 			"time": 0.0,
-			"stopped": stopped,
-			# "zcd": { k: None for k in self.crossings }
+			"stopped": stopped
 		}
 
 		self.simulator = None
 		self.reinit()
+		draw(self.state["CBD"], name + ".dot")
 
 		self.inputs = {}
 		for inp in filter(lambda b: b.getBlockType() == "InputPortBlock", cbd.getBlocks()):
@@ -91,23 +247,23 @@ class CBDRunner(AtomicDEVS):
 		"""
 		return self.state["CBD"].getBlockByName(pname).getSignal("OUT1")[-1].value
 
-	def crossing_detection(self, signal, y):
+	def crossing_detection(self, signal, y, y0):
 		"""
 		Crossing root finder for a signal.
 
 		Args:
 			signal (str):   The port to detect.
 			y (float):      The value to cross.
-
-		Note:
-			This function will change in the future, presumably becoming the IVP
-			root finding algorithm. Currently, the Illinois variant of Regula Falsi
-			is used.
+			y0 (float):     Y-value of the lower end of the interval.
 		"""
-		F = lambda t: self.crossing_function(t - self.state["time"], signal)
+		def F(t):
+			h = t - self.state["time"]
+			if h == 0:
+				return y0
+			return self.crossing_function(h, signal)
 		t1 = self.state["time"]
 		t2 = t1 + self.state["delta_t"]
-		return CrossingDetection.regula_falsi(t1, t2, y, F)
+		return self.algo(t1, t2, y, F, **self.kwargs)
 
 	def crossing_function(self, h, signal, restore=True):
 		"""
@@ -231,15 +387,18 @@ class CBDRunner(AtomicDEVS):
 			value = self.get_signal(z)
 			# print("POST", z, self.state["CBD"].getBlockByName(z).getSignal("OUT1")[-1])
 			if (old[z] - y) * (value - y) < 0:
+				# print(old[z], value, y, z, self.state["time"], self.state["delta_t"])
 				# A crossing will happen!
 				# print("CROSSING:", old[z], value, y)
-				cds.setdefault(self.crossing_detection(z, y), []).append(z)
+				cds.setdefault(self.crossing_detection(z, y, old[z]), []).append(z)
 		if len(cds) > 0:
 			fzc = min(cds)
 			self.state["zero_crossing"] = cds[fzc]
 			h = fzc - self.state["time"]
 			self.state["delta_t"] = h
 
+			# print("CROSSING HAPPENED")
+
 			self.crossing_function(h, None, False)
 		else:
 			self.set_delta(float('inf'))
@@ -321,74 +480,11 @@ def prepare_cbd(model, initials):
 	cbd.addConnection(Mname, clock, input_port_name='h')
 	return cbd, Hname
 
-
-class CrossingDetection:
-	"""
-	Helper class that implements the crossing detection algorithms.
-
-	The following description concerns the default arguments for all functions.
-	On top of that, there may be some additional arguments defined, as listed in
-	the specific documentations below.
-
-	Args:
-		t1 (float):     The x-value of the lower bound of the interval.
-		t2 (float):     The x-value of the higher bound of the interval.
-		y (float):      The value for which a crossing must be checked.
-		f:              A function that should return the y-value for a given x (or t).
-	"""
-	@staticmethod
-	def linear(t1, t2, y, f, **kwargs):
-		"""
-		Finds the root of the crossing using linear interpolation.
-		No additional function calls or arguments are used.
-		"""
-		y1 = f(t1)
-		y2 = f(t2)
-		if y1 == y2:
-			return y1
-		return (t2 - t1) / (y2 - y1) * (y - y1) + t1
-
-	@staticmethod
-	def regula_falsi(t1, t2, y, f, **kwargs):
-		"""
-		Implements the Illinois algorithm for finding the root for a crossing problem.
-
-		Args:
-			eps (float):    Half of the upper bound for the relative error.
-							Defaults to 1e-5.
-			n (int):        The maximal amount of iterations to compute. Defaults to
-							5 million iterations.
-
-		See Also:
-			https://en.wikipedia.org/wiki/Regula_falsi
-		"""
-		eps = kwargs.get("eps", 1e-5)
-		n = kwargs.get("n", 5 * 1000 * 1000)
-		y1 = f(t1) - y
-		y2 = f(t2) - y
-		assert y1 * y2 < 0, "No crossing possible in given range"
-		tn, yn = t1, y1
-		side = 0
-		for i in range(n):
-			if abs(t1 - t2) < eps * abs(t1 + t2): break
-			tn = (y1 * t2 - y2 * t1) / (y1 - y2)
-			yn = f(tn) - y
-			if yn * y2 > 0:
-				t2, y2 = tn, yn
-				if side == -1:
-					y1 /= 2
-				side = -1
-			elif yn * y1 > 0:
-				t1, y1 = tn, yn
-				if side == 1:
-					y2 /= 2
-				side = 1
-			else:
-				break
-		return tn
-
 if __name__ == '__main__':
 	import numpy as np
 	def f(x):
 		return np.cos(x) - x ** 3
-	print(CrossingDetection.regula_falsi(0, 1.5, 0, f, eps=1e-5))
+	print(CrossingDetection.regula_falsi(0, 1.5, 0, f))
+	# def f(x):
+	# 	return x ** 3 - 2*x
+	print(CrossingDetection.ITP(0, 1.5, 0, f, k1=0.1, k2=1.5))

+ 40 - 34
src/CBD/preprocessing/rungekutta.py

@@ -3,6 +3,7 @@ This module contains all the logic for Runge-Kutta preprocessing.
 """
 from CBD.CBD import CBD
 from CBD.lib.std import *
+from CBD.converters.CBDDraw import draw
 
 class RKPreprocessor:
 	r"""
@@ -69,6 +70,7 @@ class RKPreprocessor:
 
 		# 2. Create an RK-model, based on the given tableau
 		RK = self.create_RK(IVP)
+		# draw(RK, "test.dot")
 
 		# 3. Substitute the RK-model collection in the original CBD
 		outputs = original.getSignals().keys()
@@ -76,7 +78,8 @@ class RKPreprocessor:
 		new_model = CBD(original.getBlockName(), inputs, outputs)
 		new_model.addBlock(RK)
 		for inp in inputs:
-			new_model.addConnection(inp, RK, inp)
+			if RK.hasBlock(inp):
+				new_model.addConnection(inp, RK, inp)
 		old_clock = original.getClock()
 		new_model.addBlock(Clock("clock", old_clock.getTime(0) - old_clock.getRelativeTime(0)))
 		new_model.addConnection("clock", RK, 'time', 'time')
@@ -88,7 +91,7 @@ class RKPreprocessor:
 			new_model.addConnection(RK, "HDelay", output_port_name="h_new")
 			new_model.addConnection("HIC", "HDelay", input_port_name="IC")
 			new_model.addConnection("HDelay", "clock", input_port_name="h")
-			new_model.addConnection("HDelay", RK, input_port_name="h")
+			new_model.addConnection("clock", RK, input_port_name="h", output_port_name='delta')
 		else:
 			# TODO: take delta from original
 			new_model.addBlock(ConstantBlock("clock-delta", self._h_range[0]))
@@ -247,7 +250,10 @@ class RKPreprocessor:
 			# Link the output
 			p = plinks[block.getBlockName()]
 			fin = block.getBlockConnectedToInput("IN1")
-			IVP.addConnection(fin.block.getBlockName(), "OUT%d" % p, None, fin.output_port)
+			fname = fin.block.getBlockName()
+			if fname in plinks:
+				fname = "IN%d" % plinks[fname]
+			IVP.addConnection(fname, "OUT%d" % p, None, fin.output_port)
 		return IVP, plinks
 
 	def create_RK(self, f):
@@ -453,41 +459,41 @@ if __name__ == '__main__':
 	DELTA_T = 0.1
 
 	class Test(CBD):
-		def __init__(self, block_name):
-			CBD.__init__(self, block_name, input_ports=[], output_ports=['y'])
-
-			# Create the Blocks
-			self.addBlock(IntegratorBlock("int"))
-			self.addBlock(ConstantBlock("IC", value=(0)))
+		def __init__(self, name):
+			super().__init__(name, [], ['v', 'x'])
+
+			self.addBlock(ConstantBlock('x0', 0))
+			self.addBlock(ConstantBlock('v0', 0))
+			self.addBlock(ConstantBlock('k', 0.15))
+			self.addBlock(ConstantBlock("five", 5))
+			self.addBlock(NegatorBlock("neg"))
+			self.addBlock(AdderBlock("sum", 3))
 			self.addBlock(ProductBlock("mult"))
-			self.addBlock(AdderBlock("sum"))
-			self.addBlock(ConstantBlock("one", value=(1)))
-			self.addBlock(ConstantBlock("delta_t", value=(DELTA_T)))
-
-			# self.addBlock(IntegratorBlock("int2"))
-			# self.addBlock(ConstantBlock("seven", 7))
-			# self.addBlock(AdderBlock("sum7"))
-
-			# Create the Connections
-			self.addConnection("IC", "int", output_port_name='OUT1', input_port_name='IC')
-			self.addConnection("int", "mult", output_port_name='OUT1')
-			self.addConnection("int", "mult", output_port_name='OUT2')
-			self.addConnection("int", "y", output_port_name='OUT1')
-			self.addConnection("mult", "sum", output_port_name='OUT1', input_port_name='IN2')
-			self.addConnection("one", "sum", output_port_name='OUT1', input_port_name='IN1')
-			self.addConnection("sum", "int", output_port_name='OUT1', input_port_name='IN1')
-			self.addConnection("delta_t", "int", output_port_name='OUT1', input_port_name='delta_t')
-
-			# self.addConnection("int", "sum7")
-			# self.addConnection("clock-clock", "sum7", output_port_name='rel_time')
-			# self.addConnection("seven", "sum7")
-			# self.addConnection("sum7", "int2")
+			self.addBlock(IntegratorBlock("Iv"))
+			self.addBlock(IntegratorBlock("Ix"))
+
+			self.addConnection("five", "sum")
+			self.addConnection("v0", "neg")
+			self.addConnection("neg", "sum")
+			self.addConnection("sum", "mult")
+			self.addConnection("k", "mult")
+			self.addConnection("mult", "Iv")
+			self.addConnection("Iv", "sum")
+			self.addConnection("Iv", "v")
+			self.addConnection("Iv", "Ix")
+			self.addConnection("Ix", "x")
+			self.addConnection("v0", "Iv", input_port_name='IC')
+			self.addConnection("x0", "Ix", input_port_name='IC')
+
+			self.addFixedRateClock("clock", 0.1)
+			self.addConnection("clock-clock", "Iv", output_port_name="delta", input_port_name='delta_t')
+			self.addConnection("clock-clock", "Ix", output_port_name="delta", input_port_name='delta_t')
 
 	test = Test("Test")
-	test.addFixedRateClock("clock", 0.1)
+	# test.addFixedRateClock("clock", 0.1)
 	prep = RKPreprocessor(BT.RKF45(), atol=2e-5, hmin=1e-8, safety=.84)
 	model = prep.preprocess(test)
-	draw(model.findBlock("RK.error")[0], "test.dot")
+	draw(model, "test.dot")
 	# model = Test("Test")
 
 	from CBD.simulator import Simulator
@@ -495,7 +501,7 @@ if __name__ == '__main__':
 	sim.setDeltaT(0.2)
 	sim.run(1.4)
 
-	s = model.getSignal("y")
+	s = model.getSignal("v")
 	L = len(s)
 	errs = model.findBlock("RK.error")[0].getSignal("error")
 	hs = model.findBlock("RK.error")[0].getSignal("h_new")

+ 0 - 93
src/CBD/preprocessing/test.dot

@@ -1,93 +0,0 @@
-// CBD model of the Test.RK.error block
-// Created with CBD.converters.CBDDraw
-digraph model {
- splines=ortho;
- label=<<B>Test.RK.error (CBD)</B>>;
- labelloc="t";
- fontsize=20;
- node_139764280436912 [label="h", shape=none];
- inter_139764280436912_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280436912 -> inter_139764280436912_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437056 [label="y_1", shape=none];
- inter_139764280437056_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437056 -> inter_139764280437056_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437152 [label="z_1", shape=none];
- inter_139764280437152_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437152 -> inter_139764280437152_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437248 [label="h_new", shape=none];
- inter_139764280418112_OUT1 -> node_139764280437248 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
- node_139764280437344 [label="error", shape=none];
- inter_139764280437488_OUT1 -> node_139764280437344 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
- node_139764280436960 [label=" ConstantBlock\n(Tol)\n2e-05", shape=ellipse];
- inter_139764280436960_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280436960 -> inter_139764280436960_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437440 [label=" ConstantBlock\n(Eps)\n1e-20", shape=ellipse];
- inter_139764280437440_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437440 -> inter_139764280437440_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437488 [label="MaxBlock\n(Max)", shape=box];
- inter_139764280437440_OUT1 -> node_139764280437488 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437776_OUT1 -> node_139764280437488 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437488_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437488 -> inter_139764280437488_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437584 [label="NegatorBlock\n(Neg_1)", shape=box];
- inter_139764280437056_OUT1 -> node_139764280437584 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437584_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437584 -> inter_139764280437584_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437680 [label="AdderBlock\n(Sum_1)", shape=box];
- inter_139764280437584_OUT1 -> node_139764280437680 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437152_OUT1 -> node_139764280437680 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437680_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437680 -> inter_139764280437680_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437776 [label="AbsBlock\n(Abs_1)", shape=box];
- inter_139764280437680_OUT1 -> node_139764280437776 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437776_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437776 -> inter_139764280437776_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437536 [label="InverterBlock\n(hinv)", shape=box];
- inter_139764280436912_OUT1 -> node_139764280437536 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437536_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437536 -> inter_139764280437536_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437824 [label="ProductBlock\n(R)", shape=box];
- inter_139764280437488_OUT1 -> node_139764280437824 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437536_OUT1 -> node_139764280437824 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437824_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437824 -> inter_139764280437824_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437920 [label="InverterBlock\n(Rinv)", shape=box];
- inter_139764280437824_OUT1 -> node_139764280437920 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437920_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437920 -> inter_139764280437920_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280437872 [label="ProductBlock\n(RinvMult)", shape=box];
- inter_139764280437920_OUT1 -> node_139764280437872 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280436960_OUT1 -> node_139764280437872 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280437872_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280437872 -> inter_139764280437872_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280438016 [label="RootBlock\n(Root)", shape=box];
- inter_139764280437872_OUT1 -> node_139764280438016 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280438064_OUT1 -> node_139764280438016 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280438016_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280438016 -> inter_139764280438016_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280438064 [label=" ConstantBlock\n(q)\n4", shape=ellipse];
- inter_139764280438064_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280438064 -> inter_139764280438064_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280438112 [label=" ConstantBlock\n(S)\n0.84", shape=ellipse];
- inter_139764280438112_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280438112 -> inter_139764280438112_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280438160 [label="ProductBlock\n(SMult)", shape=box];
- inter_139764280438112_OUT1 -> node_139764280438160 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280438016_OUT1 -> node_139764280438160 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280438160_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280438160 -> inter_139764280438160_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280438256 [label=" ClampBlock\n(Clamp)\n[0.1, 4.0]", shape=box];
- inter_139764280438160_OUT1 -> node_139764280438256 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280438256_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280438256 -> inter_139764280438256_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280416720 [label="ProductBlock\n(HMult)", shape=box];
- inter_139764280436912_OUT1 -> node_139764280416720 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280438256_OUT1 -> node_139764280416720 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280416720_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280416720 -> inter_139764280416720_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_139764280418112 [label=" ClampBlock\n(HClamp)\n[1e-08, 0.1]", shape=box];
- inter_139764280416720_OUT1 -> node_139764280418112 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_139764280418112_OUT1 [shape=point, width=0.01, height=0.01];
- node_139764280418112 -> inter_139764280418112_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
-
-}

+ 2 - 1
src/CBD/simulator.py

@@ -3,7 +3,7 @@ import time
 import threading
 from . import naivelog
 from .depGraph import createDepGraph
-from .solver import GaussianJordanLinearSolver
+from .solver import GaussianJordanLinearSolver, SympySolver
 from .realtime.threadingBackend import ThreadingBackend, Platform
 from .util import PYTHON_VERSION, hash64
 from .scheduling import TopologicalScheduler
@@ -111,6 +111,7 @@ class Simulator:
 		}
 		
 		# TODO: make this variable, given more solver implementations
+		# self.__solver = SympySolver(self.__logger)
 		self.__solver = GaussianJordanLinearSolver(self.__logger)
 
 	def run(self, term_time=None):

+ 59 - 0
src/CBD/solver.py

@@ -263,3 +263,62 @@ class Matrix:
 		outer = absolute // self.__max_list_size
 		inner = absolute % self.__max_list_size
 		self.data[outer][inner] = value
+
+
+try:
+	import sympy
+	# TODO: non-unique solutions?
+	class SympySolver(Solver):
+		def checkValidity(self, path, component):
+			raise NotImplementedError("The Sympy Solver is not finished yet, so please refrain from using it.")
+
+		def constructInput(self, component, curIt):
+			eqs = {}
+			for i, block in enumerate(component):
+				args = []
+				for x in self.__dependencies(block):
+					if x not in component:
+						args.append(x.getSignal()[curIt].value)
+					else:
+						args.append(sympy.symbols('x%d' % component.index(x)))
+				eqs['x%d' % i] = self.__OPERATIONS[block.getBlockType()](args, block)
+			return eqs
+
+		def solve(self, solverInput):
+			sol = []
+			eqs = []
+			answer = [0] * len(solverInput)
+			for k, v in solverInput.items():
+				x = sympy.symbols(k)
+				sol.append(x)
+				eqs.append(v - x)
+			solution = sympy.nonlinsolve(eqs, sol)
+			print(solverInput, solution)
+
+		# TODO: Clamp, MUX, Split, LTE, Eq, LT, not, and, or, delay
+		__OPERATIONS = {
+			"AdderBlock": lambda l, _: sum(l),
+			"ProductBlock": lambda l, _: reduce((lambda a, b: a * b), l),
+			"NegatorBlock": lambda l, _: -l[0],
+			"InverterBlock": lambda l, _: 1.0/l[0],
+			"ModuloBlock": lambda l, _: l[0] % l[1],
+			"RootBlock": lambda l, _: sympy.root(l[0], l[1]),
+			"PowerBlock": lambda l, _: l[0] ** l[1],
+			"AbsBlock": lambda l, _: abs(l[0]),
+			"IntBlock": lambda l, _: sympy.floor(l[0]),
+			"GenericBlock": lambda l, b: getattr(sympy, b.getBlockOperator())(l[0]),
+			"MaxBlock": lambda l: sympy.Max(*l),
+			"MinBlock": lambda l: sympy.Min(*l),
+		}
+
+		@staticmethod
+		def __dependencies(block):
+			blocks = []
+			for s in block.getInputPortNames():
+				b, op = block.getBlockConnectedToInput(s)
+				if isinstance(b, CBD):
+					b = b.getBlockByName(op)
+				blocks.append(b)
+			return blocks
+
+except: pass