ソースを参照

More work on RKF

rparedis 4 年 前
コミット
31a93123fd

+ 11 - 5
src/CBD/converters/CBDDraw.py

@@ -12,8 +12,12 @@ def draw(cbd, filename, colors=None):
 	Output :class:`CBD` as a graphviz script to filename.
 
 	Warning:
-		This function may be removed in the future as DrawIO becomes
-		more important.
+		This function may be removed in the future as DrawIO becomes more important.
+
+	Note:
+		The resulting Graphviz file might look "clunky" and messy when rendering with
+		the standard dot engine. The :code:`neato`, :code:`twopi` and :code:`circo`
+		engines might provide a cleaner and more readable result.
 
 	Args:
 		cbd (CBD):      The :class:`CBD` to draw.
@@ -26,7 +30,7 @@ def draw(cbd, filename, colors=None):
 
 	write("""// CBD model of the {n} block
 // Created with CBD.converters.CBDDraw
-digraph graphname {{
+digraph model {{
  splines=ortho;
  label=<<B>{n} ({t})</B>>;
  labelloc=\"t\";
@@ -44,9 +48,11 @@ digraph graphname {{
 			block:  The block to write.
 		"""
 		if isinstance(block, ConstantBlock):
-			label = block.getBlockType() + "\\n(" + block.getBlockName() + ")\\n" + str(round(block.getValue(), 6))
+			label = " {}\\n({})\\n{}".format(block.getBlockType(), block.getBlockName(), block.getValue())
 		elif isinstance(block, GenericBlock):
-			label = block.getBlockType() + "\\n(" + block.getBlockName() + ")\\n" + str(block.getBlockOperator())
+			label = " {}\\n({})\\n{}".format(block.getBlockType(), block.getBlockName(), block.getBlockOperator())
+		elif isinstance(block, ClampBlock) and block._use_const:
+			label = " {}\\n({})\\n[{}, {}]".format(block.getBlockType(), block.getBlockName(), block.min, block.max)
 		elif isinstance(block, (InputPortBlock, OutputPortBlock)):
 			label = block.getBlockName()
 		else:

+ 0 - 9
src/CBD/converters/test.dot

@@ -1,9 +0,0 @@
-
-digraph graphname {
- node_140327829132816 [label="ConstantBlock (F6cEAfyq)\n7.0"];
-node_140327829132624 [label="ConstantBlock (F6cEAfvq)\n6.0"];
-node_140327829132384 [label="AdderBlock (F6cEAfrG)"];
-node_140327829132816 -> node_140327829132384 [label="OUT1 / IN1"];
-node_140327829132624 -> node_140327829132384 [label="OUT1 / IN2"];
-
-}

+ 8 - 2
src/CBD/lib/std.py

@@ -51,12 +51,16 @@ class InverterBlock(BaseBlock):
 	"""
 	The invertblock will output 1/IN
 	"""
-	def __init__(self, block_name):
+	def __init__(self, block_name, tolerance=1e-30):
 		BaseBlock.__init__(self, block_name, ["IN1"], ["OUT1"])
+		self._tolerance = tolerance
 
 	def compute(self, curIteration):
 		# TO IMPLEMENT
-		self.appendToSignal(1 / self.getInputSignal(curIteration, "IN1").value)
+		input = self.getInputSignal(curIteration, "IN1").value
+		if abs(input) < self._tolerance:
+			raise ZeroDivisionError("InverterBlock received input less than {}.".format(self._tolerance))
+		self.appendToSignal(1.0 / input)
 
 
 class AdderBlock(BaseBlock):
@@ -581,6 +585,8 @@ class Clock(CBD):
 		- :code:`rel_time`: The relative simulation time, ignoring the start time.
 	"""
 	def __init__(self, block_name, start_time=0.0):
+		# TODO: simplify if start_time is 0
+		# TODO: rel_time must not depend on delay + h !!
 		CBD.__init__(self, block_name, ["h"], ["time", "rel_time"])
 		self.__start_time = start_time
 

+ 27 - 22
src/CBD/preprocessing/rk-notes/rkf.py

@@ -4,7 +4,7 @@ import time
 
 class rkf():
 
-    def __init__(self,f, a, b, x0, atol=1e-8, rtol=1e-6, hmax=1e-1, hmin=1e-40,plot_stepsize=False,show_info=True):
+    def __init__(self,f, a, b, x0, atol=1e-8, rtol=1e-6, hmax=1e-1, hmin=1e-40, safety=0.94, plot_stepsize=False,show_info=True):
         self.f=f
         self.a=a
         self.b=b
@@ -13,6 +13,7 @@ class rkf():
         self.rtol=rtol
         self.hmax=hmax
         self.hmin=hmin
+        self.safety = safety
         self.plot_stepsize=plot_stepsize
         self.show_info=show_info
 
@@ -73,7 +74,7 @@ class rkf():
             k6 = h * self.f(t + a6 * h, x + b61 * k1 + b62 * k2 + b63 * k3 + b64 * k4 + b65 * k5)
 
             r = abs( r1 * k1 + r3 * k3 + r4 * k4 + r5 * k5 + r6 * k6 ) / h
-            r = r / (self.atol+self.rtol*(abs(x)+abs(k1)))
+            r = r / (self.atol + self.rtol*(abs(x)+abs(k1)))
             if len( np.shape( r ) ) > 0:
                 r = max( r )
             if r <= 1:
@@ -81,13 +82,12 @@ class rkf():
                 x = x + c1 * k1 + c3 * k3 + c4 * k4 + c5 * k5
                 T = np.append( T, t )
                 X = np.append( X, [x], 0 )
-            h = h * min( max( 0.94 * ( 1 / r )**0.25, 0.1 ), 4.0 )
+            h = h * min( max( self.safety * (1 / r)**0.25, 0.1 ), 4.0 )
             if h > self.hmax:
                 h = self.hmax
-            elif h < self.hmin or t==t-h:
+            elif h < self.hmin:
                 raise RuntimeError("Error: Could not converge to the required tolerance.")
-                break
-        
+
         if self.show_info is True:
             print('Execution time:',time.time() - start_time, 'seconds')
             print('Number of data points:',len(T))
@@ -102,11 +102,12 @@ class rkf():
             plt.tight_layout()
             plt.show()
 
-        return (T,X)
+        return T, X
 
 if __name__ == '__main__':
     import numpy as np
     import matplotlib.pyplot as plt
+    import pandas as pd
     import time
     import matplotlib.animation as animation
 
@@ -121,25 +122,29 @@ if __name__ == '__main__':
         return np.array([vx,vy,vz])
 
     def test(t, u):
-        return u**2 + 1
+        # return u - t**2 + 1
+        return 1 + u**2
 
-    x0=0
+    x0 = 0
     # x0=[2,2,2]
 
     # t,u  = rkf( f=lorenz, a=0, b=1e+1, x0=x0, atol=1e-8, rtol=1e-6 , hmax=1e-1, hmin=1e-40,plot_stepsize=True).solve()
-    t,u  = rkf( f=test, a=0, b=1e+1, x0=x0, atol=1e-5, rtol=1e-5 , hmax=5e-1, hmin=1e-40, plot_stepsize=True).solve()
-
-    x,y,z= u.T
-
-    plt.style.use('dark_background')
-    fig = plt.figure()
-    ax = fig.gca(projection='3d')
-    ax.set_axis_off()
-    ax.plot(x,y,z,lw=0.5,c='whitesmoke')
-    # plt.show()
-
-    def rotate(angle):
-        ax.view_init(elev=7.,azim=angle)
+    t, u  = rkf( f=test, a=0, b=1.4, x0=x0, atol=2e-5, rtol=0, hmax=0.1, safety=.84, plot_stepsize=False).solve()
+
+    # x, y = u.T
+
+    df = pd.DataFrame({"t": t, "u": u})
+    print(df)
+
+    # plt.style.use('dark_background')
+    # fig = plt.figure()
+    # ax = fig.gca(projection='3d')
+    # ax.set_axis_off()
+    # ax.plot(x,y,z,lw=0.5,c='whitesmoke')
+    # # plt.show()
+    #
+    # def rotate(angle):
+    #     ax.view_init(elev=7.,azim=angle)
 
     # print("Making animation")
     # rot_animation = animation.FuncAnimation(fig, rotate, frames=np.arange(0, 600, 2), interval=36)

+ 44 - 14
src/CBD/preprocessing/rungekutta.py

@@ -19,14 +19,19 @@ class RKPreprocessor:
 							may be done. When this is a normal tableau, mere approximation will
 							happen. When it is an extended tableau, the scale factor for the delta
 							will also be computed.
-		tolerance (float):  The tolerance for precision in approximating, given that the tableau is
-							an extended tableau. Defaults to 0.005.
+		atol (float):       The absolute tolerance for precision in approximating, given that the
+							tableau is an extended tableau. Defaults to 1e-8.
+		hmin (float):       Minimal value for the delta, given that the tableau is an extended
+							tableau. Defaults to 1e-40.
+		hmax (float):       Maximal value for the delta, given that the tableau is an extended
+							tableau. Defaults to 1e-1.
 		safety (float):     Safety factor for the error computation. Must be in (0, 1], preferrably
 							on the high end of the range. Defaults to 0.9.
 	"""
-	def __init__(self, tableau, tolerance=0.005, safety=0.9):
+	def __init__(self, tableau, atol=1e-8, hmin=1e-40, hmax=1e-1, safety=0.9):
 		self._tableau = tableau
-		self._tolerance = tolerance
+		self._tolerance = atol
+		self._h_range = hmin, hmax
 		self._safety = safety
 
 	def preprocess(self, original):
@@ -190,6 +195,8 @@ class RKPreprocessor:
 		plinks = {}
 		iblocks = []
 		for block in blocks:
+			if isinstance(block, DelayBlock):
+				raise RuntimeError("Impossible to construct Runge-Kutta model for Delay Differential Equations!")
 			if isinstance(block, IntegratorBlock):
 				# Identify all integrators and give them their in- and outputs
 				i += 1
@@ -413,15 +420,18 @@ class RKPreprocessor:
 			Err.addConnection("Sum_%d" % j, "Abs_%d" % j)
 			Err.addConnection("Abs_%d" % j, "Max")
 
-		Err.addBlock(ProductBlock("Mult", 3))
+		Err.addBlock(ProductBlock("Mult"))
 		Err.addBlock(ProductBlock("Frac", 3))
 		Err.addBlock(ConstantBlock("S", self._safety))
 		Err.addBlock(ConstantBlock("q", self._tableau.getOrder()))
 		Err.addBlock(InverterBlock("Inv"))
 		Err.addBlock(ConstantBlock("Eps", self._tolerance))
 		Err.addBlock(RootBlock("Root"))
+		Err.addBlock(ProductBlock("MultH"))
+		Err.addBlock(ClampBlock("Clamp", 0.1, 4.0))
+		Err.addBlock(ClampBlock("ClampH", self._h_range[0], self._h_range[1]))
 
-		Err.addConnection("h", "Mult")
+		Err.addConnection("h", "MultH")
 		Err.addConnection("S", "Mult")
 
 		Err.addConnection("Max", "Inv")
@@ -431,10 +441,16 @@ class RKPreprocessor:
 		Err.addConnection("Frac", "Root", input_port_name="IN1")
 		Err.addConnection("q", "Root", input_port_name="IN2")
 		Err.addConnection("Root", "Mult")
-		Err.addConnection("Mult", "h_new")
+		Err.addConnection("MultH", "ClampH")
+		Err.addConnection("ClampH", "h_new")
+		Err.addConnection("Clamp", "MultH")
+		Err.addConnection("Mult", "Clamp")
 
 		Err.addConnection("Max", "error")
 
+		# TODO: enforce positive tolerance
+		# TODO: if Max <= Eps * h: don't progress time
+
 		return Err
 
 
@@ -476,14 +492,14 @@ if __name__ == '__main__':
 
 	test = Test("Test")
 	test.addFixedRateClock("clock", 0.1)
-	prep = RKPreprocessor(BT.RKF45(), 2e-5, .5**.25)
+	prep = RKPreprocessor(BT.RKF45(), atol=2e-5, safety=.84)
 	model = prep.preprocess(test)
 	draw(model.findBlock("RK.error")[0], "test.dot")
 	# model = Test("Test")
 
 	from CBD.simulator import Simulator
 	sim = Simulator(model)
-	sim.setDeltaT(0.1)
+	sim.setDeltaT(0.2)
 	sim.run(1.4)
 
 	s = model.getSignal("y")
@@ -492,10 +508,24 @@ if __name__ == '__main__':
 	hs = model.findBlock("RK.error")[0].getSignal("h_new")
 	# errs = hs = s
 
-	print("+------------+------------+------------+------------+")
-	print("|    TIME    |    VALUE   |      H     |    ERROR   |")
-	print("+------------+------------+------------+------------+")
+	# print([x for _, x in errs])
+
+	import numpy as np
+	print("+------------+------------+------------+------------+------------+------------+")
+	print("|    TIME    |    VALUE   |     TAN    |    ERROR   |   OFFSET   |    DELTA   |")
+	print("+------------+------------+------------+------------+------------+------------+")
 	for i in range(L):
 		t, v = s[i]
-		print("| {t:10.7f} | {v:10.7f} | {h:10.7f} | {e:10.7f} |".format(t=t, v=v, h=hs[i].value, e=errs[i].value))
-	print("+------------+------------+------------+------------+")
+		actual = np.tan(t)
+		error = abs(actual - v)
+		print("| {t:10.7f} | {v:10.7f} | {h:10.7f} | {e:10.7f} | {o:10.7f} | {d:10.7f} |"
+		      .format(t=t, v=v, h=actual, e=error, o=errs[i].value, d=hs[i].value))
+	print("+------------+------------+------------+------------+------------+------------+")
+
+	import matplotlib.pyplot as plt
+
+	fig, ax = plt.subplots()
+	ax.plot(np.arange(0.0, 1.4, 0.01), [np.tan(t) for t in np.arange(0.0, 1.4, 0.01)], label="tan(t)")
+	ax.plot([t for t, _ in s], [v for _, v in s], label="estimate")
+	ax.legend()
+	plt.show()

+ 73 - 61
src/CBD/preprocessing/test.dot

@@ -1,69 +1,81 @@
 // CBD model of the Test.RK.error block
 // Created with CBD.converters.CBDDraw
-digraph graphname {
+digraph model {
  splines=ortho;
  label=<<B>Test.RK.error (CBD)</B>>;
  labelloc="t";
  fontsize=20;
- node_140355633174512 [label="h", shape=none];
- inter_140355633174512_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633174512 -> inter_140355633174512_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633174656 [label="y_1", shape=none];
- inter_140355633174656_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633174656 -> inter_140355633174656_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633174752 [label="z_1", shape=none];
- inter_140355633174752_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633174752 -> inter_140355633174752_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633174848 [label="h_new", shape=none];
- inter_140355633175040_OUT1 -> node_140355633174848 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
- node_140355633174944 [label="error", shape=none];
- inter_140355633174560_OUT1 -> node_140355633174944 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
- node_140355633174560 [label="MaxBlock\n(Max)", shape=box];
- inter_140355633175280_OUT1 -> node_140355633174560 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633174560_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633174560 -> inter_140355633174560_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175088 [label="NegatorBlock\n(Neg_1)", shape=box];
- inter_140355633174656_OUT1 -> node_140355633175088 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175088_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175088 -> inter_140355633175088_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175184 [label="AdderBlock\n(Sum_1)", shape=box];
- inter_140355633175088_OUT1 -> node_140355633175184 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633174752_OUT1 -> node_140355633175184 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175184_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175184 -> inter_140355633175184_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175280 [label="AbsBlock\n(Abs_1)", shape=box];
- inter_140355633175184_OUT1 -> node_140355633175280 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175280_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175280 -> inter_140355633175280_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175040 [label="ProductBlock\n(Mult)", shape=box];
- inter_140355633174512_OUT1 -> node_140355633175040 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175424_OUT1 -> node_140355633175040 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175616_OUT1 -> node_140355633175040 [headlabel="IN3", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175040_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175040 -> inter_140355633175040_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175376 [label="ProductBlock\n(Frac)", shape=box];
- inter_140355633175568_OUT1 -> node_140355633175376 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175472_OUT1 -> node_140355633175376 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633174512_OUT1 -> node_140355633175376 [headlabel="IN3", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175376_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175376 -> inter_140355633175376_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175424 [label="ConstantBlock\n(S)\n0.840896", shape=ellipse];
- inter_140355633175424_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175424 -> inter_140355633175424_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175328 [label="ConstantBlock\n(q)\n4", shape=ellipse];
- inter_140355633175328_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175328 -> inter_140355633175328_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175472 [label="InverterBlock\n(Inv)", shape=box];
- inter_140355633174560_OUT1 -> node_140355633175472 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175472_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175472 -> inter_140355633175472_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175568 [label="ConstantBlock\n(Eps)\n2e-05", shape=ellipse];
- inter_140355633175568_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175568 -> inter_140355633175568_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
- node_140355633175616 [label="RootBlock\n(Root)", shape=box];
- inter_140355633175376_OUT1 -> node_140355633175616 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175328_OUT1 -> node_140355633175616 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
- inter_140355633175616_OUT1 [shape=point, width=0.01, height=0.01];
- node_140355633175616 -> inter_140355633175616_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015200 [label="h", shape=none];
+ inter_139845894015200_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015200 -> inter_139845894015200_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015344 [label="y_1", shape=none];
+ inter_139845894015344_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015344 -> inter_139845894015344_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015440 [label="z_1", shape=none];
+ inter_139845894015440_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015440 -> inter_139845894015440_OUT1 [taillabel="", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015536 [label="h_new", shape=none];
+ inter_139845894016400_OUT1 -> node_139845894015536 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_139845894015632 [label="error", shape=none];
+ inter_139845894015248_OUT1 -> node_139845894015632 [headlabel="", arrowhead="normal", arrowtail="none", dir=both];
+ node_139845894015248 [label="MaxBlock\n(Max)", shape=box];
+ inter_139845894015968_OUT1 -> node_139845894015248 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015248_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015248 -> inter_139845894015248_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015776 [label="NegatorBlock\n(Neg_1)", shape=box];
+ inter_139845894015344_OUT1 -> node_139845894015776 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015776_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015776 -> inter_139845894015776_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015872 [label="AdderBlock\n(Sum_1)", shape=box];
+ inter_139845894015776_OUT1 -> node_139845894015872 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015440_OUT1 -> node_139845894015872 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015872_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015872 -> inter_139845894015872_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015968 [label="AbsBlock\n(Abs_1)", shape=box];
+ inter_139845894015872_OUT1 -> node_139845894015968 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015968_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015968 -> inter_139845894015968_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894015728 [label="ProductBlock\n(Mult)", shape=box];
+ inter_139845894016112_OUT1 -> node_139845894015728 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016256_OUT1 -> node_139845894015728 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015728_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894015728 -> inter_139845894015728_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016064 [label="ProductBlock\n(Frac)", shape=box];
+ inter_139845894016208_OUT1 -> node_139845894016064 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016160_OUT1 -> node_139845894016064 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894015200_OUT1 -> node_139845894016064 [headlabel="IN3", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016064_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016064 -> inter_139845894016064_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016112 [label=" ConstantBlock\n(S)\n0.84", shape=ellipse];
+ inter_139845894016112_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016112 -> inter_139845894016112_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016016 [label=" ConstantBlock\n(q)\n4", shape=ellipse];
+ inter_139845894016016_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016016 -> inter_139845894016016_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016160 [label="InverterBlock\n(Inv)", shape=box];
+ inter_139845894015248_OUT1 -> node_139845894016160 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016160_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016160 -> inter_139845894016160_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016208 [label=" ConstantBlock\n(Eps)\n2e-05", shape=ellipse];
+ inter_139845894016208_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016208 -> inter_139845894016208_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016256 [label="RootBlock\n(Root)", shape=box];
+ inter_139845894016064_OUT1 -> node_139845894016256 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016016_OUT1 -> node_139845894016256 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016256_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016256 -> inter_139845894016256_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016352 [label="ProductBlock\n(MultH)", shape=box];
+ inter_139845894015200_OUT1 -> node_139845894016352 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016448_OUT1 -> node_139845894016352 [headlabel="IN2", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016352_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016352 -> inter_139845894016352_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016448 [label=" ClampBlock\n(Clamp)\n[0.1, 4.0]", shape=box];
+ inter_139845894015728_OUT1 -> node_139845894016448 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016448_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016448 -> inter_139845894016448_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
+ node_139845894016400 [label=" ClampBlock\n(ClampH)\n[1e-40, 0.1]", shape=box];
+ inter_139845894016352_OUT1 -> node_139845894016400 [headlabel="IN1", arrowhead="normal", arrowtail="none", dir=both];
+ inter_139845894016400_OUT1 [shape=point, width=0.01, height=0.01];
+ node_139845894016400 -> inter_139845894016400_OUT1 [taillabel="OUT1", arrowtail="invempty", arrowhead="none", dir=both];
 
 }