Преглед изворни кода

Runge-Kutta now works for fixed-rate

rparedis пре 4 година
родитељ
комит
f3be2c22de
5 измењених фајлова са 71 додато и 74 уклоњено
  1. 4 13
      src/CBD/CBDDraw.py
  2. 27 1
      src/CBD/lib/std.py
  3. 26 26
      src/CBD/preprocessing/rungekutta.py
  4. 13 33
      src/CBD/preprocessing/test.dot
  5. 1 1
      src/CBD/stepsize.py

+ 4 - 13
src/CBD/CBDDraw.py

@@ -28,9 +28,6 @@ digraph graphname {
 	if colors is None:
 		colors = {}
 
-	def formatName(name):
-		return re.sub("[^a-zA-Z_0-9]", "", name)
-
 	def writeBlock(block):
 		"""
 		Writes a block to graphviz.
@@ -51,7 +48,7 @@ digraph graphname {
 		if block.getBlockName() in colors:
 			col = ", color=\"{0}\", fontcolor=\"{0}\"".format(colors[block.getBlockName()])
 
-		write("{b} [label=\"{lbl}\"{shape}{col}];\n".format(b=formatName(block.getBlockName()),
+		write("{b} [label=\"{lbl}\"{shape}{col}];\n".format(b="node_%d" % id(block),
 			lbl=label,
 			shape=shape,
 			col=col))
@@ -60,16 +57,10 @@ digraph graphname {
 	for block in cbd.getBlocks():
 		writeBlock(block)
 		for (name, other) in  block.getLinksIn().items():
-			label = name
-
-			# if not name.startswith("IN"):
-			# 	label=name
-
-			if not other.output_port.startswith("OUT"):
-				label = label + " / " + other.output_port
+			label = name + " / " + other.output_port
 
-			write("{a} -> {b} [label=\"{lbl}\"];\n".format(a=formatName(other.block.getBlockName()),
-				b=formatName(block.getBlockName()),
+			write("{a} -> {b} [label=\"{lbl}\"];\n".format(a="node_%d" % id(other.block),
+				b="node_%d" % id(block),
 				lbl=label))
 
 	write("\n}")

+ 27 - 1
src/CBD/lib/std.py

@@ -8,7 +8,7 @@ import math
 __all__ = ['ConstantBlock', 'NegatorBlock', 'InverterBlock', 'AdderBlock', 'ProductBlock', 'ModuloBlock',
            'RootBlock', 'AbsBlock', 'IntBlock', 'ClampBlock', 'GenericBlock', 'MultiplexerBlock', 'LessThanBlock',
            'EqualsBlock', 'LessThanOrEqualsBlock', 'NotBlock', 'OrBlock', 'AndBlock', 'DelayBlock', 'TimeBlock',
-           'LoggingBlock', 'AddOneBlock', 'DerivatorBlock', 'IntegratorBlock', 'DeltaTBlock']
+           'LoggingBlock', 'AddOneBlock', 'DerivatorBlock', 'IntegratorBlock', 'DeltaTBlock', 'SplitBlock']
 
 class ConstantBlock(BaseBlock):
 	"""
@@ -203,6 +203,32 @@ class MultiplexerBlock(BaseBlock):
 		self.appendToSignal(self.getInputSignal(curIteration, "IN1" if select == 0 else "IN2").value)
 
 
+class SplitBlock(BaseBlock):
+	"""
+	The split block will split a signal over multiple paths.
+	While this block can generally be omitted, it may still be
+	used for clarity and clean-ness of the resulting models.
+
+	Args:
+		block_name (str):       The name of the block.
+		numberOfOutputs (int):  The amount of paths to split into.
+	"""
+	def __init__(self, block_name, numberOfOutputs=2):
+		BaseBlock.__init__(self, block_name, ["IN1"], ["OUT%d" % (i+1) for i in range(numberOfOutputs)])
+		self.__numberOfOutputs = numberOfOutputs
+
+	def compute(self, curIteration):
+		value = self.getInputSignal(curIteration).value
+		for i in range(self.__numberOfOutputs):
+			self.appendToSignal(value, "OUT%d" % (i+1))
+
+	def getNumberOfOutputs(self):
+		"""
+		Gets the total number of output ports.
+		"""
+		return self.__numberOfOutputs
+
+
 class LessThanBlock(BaseBlock):
 	"""
 	A simple block that will test if the IN1 is smaller than IN2 (output == 1 if true else 0)

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

@@ -104,12 +104,12 @@ class RKPreprocessor:
 				RK.addConnection("RK-K_%d" % (s+1), "RK-K_%d" % j, "k_%d" % (s+1))
 
 		# Initial Conditions
-		RK.addBlock(NegatorBlock("neg"))
-		RK.addBlock(AdderBlock("ICSum"))
-		RK.addConnection("RKSum", "neg")
-		RK.addConnection("neg", "ICSum")
-		RK.addConnection("IC", "ICSum")
-		RK.addConnection("ICSum", "delay", "IC")
+		# RK.addBlock(NegatorBlock("neg"))
+		# RK.addBlock(AdderBlock("ICSum"))
+		# RK.addConnection("RKSum", "neg")
+		# RK.addConnection("neg", "ICSum")
+		RK.addConnection("IC", "delay", "IC")
+		# RK.addConnection("ICSum", "delay", "IC")
 
 		# Loop
 		RK.addBlock(AdderBlock("YSum"))
@@ -148,14 +148,12 @@ class RKPreprocessor:
 				K.addConnection("k_%d" % j, "Mult_%d" % j)
 				K.addConnection("Mult_%d" % j, "KSum")
 			for y in fy:
-				K.addInputPort(y)
 				K.addBlock(AdderBlock("YSum-%s" % y))
 				K.addConnection(y, "YSum-%s" % y)
 				K.addConnection("KSum", "YSum-%s" % y)
 				K.addConnection("YSum-%s" % y, f.getBlockName(), y)
 		else:
 			for y in fy:
-				K.addInputPort(y)
 				K.addConnection(y, f.getBlockName(), y)
 
 		# Finishing Up
@@ -183,11 +181,13 @@ if __name__ == '__main__':
 			self.addBlock(AdderBlock("sum"))
 			self.addBlock(ConstantBlock("one", value=(1)))
 			self.addBlock(ConstantBlock("time", value=(DELTA_T)))
+			self.addBlock(SplitBlock("split"))
 
 			# Create the Connections
 			self.addConnection("IC", "int", output_port_name='OUT1', input_port_name='IC')
-			self.addConnection("int", "mult", output_port_name='OUT1', input_port_name='IN1')
-			self.addConnection("int", "mult", output_port_name='OUT1', input_port_name='IN2')
+			self.addConnection("int", "split")
+			self.addConnection("split", "mult", output_port_name='OUT1')
+			self.addConnection("split", "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')
@@ -196,21 +196,21 @@ if __name__ == '__main__':
 
 	prep = RKPreprocessor(BT.Heun())
 	model = prep.preprocess(Test("Test"))
-	draw(model.findBlock("RK.RK-K_2")[0], "test.dot")
+	draw(model.findBlock("RK")[0], "test.dot")
 	# model = Test("Test")
 
-	# from CBD.simulator import Simulator
-	# sim = Simulator(model)
-	# sim.setDeltaT(0.1)
-	# sim.run(1.4)
-	#
-	# s = model.getSignal("y")
-	# L = len(s)
-	#
-	# print("+------------+------------+")
-	# print("|    TIME    |    VALUE   |")
-	# print("+------------+------------+")
-	# for i in range(L):
-	# 	t, v = s[i]
-	# 	print(f"| {t:10.7f} | {v:10.7f} |")
-	# print("+------------+------------+")
+	from CBD.simulator import Simulator
+	sim = Simulator(model)
+	sim.setDeltaT(0.1)
+	sim.run(1.4)
+
+	s = model.getSignal("y")
+	L = len(s)
+
+	print("+------------+------------+")
+	print("|    TIME    |    VALUE   |")
+	print("+------------+------------+")
+	for i in range(L):
+		t, v = s[i]
+		print(f"| {t:10.7f} | {v:10.7f} |")
+	print("+------------+------------+")

+ 13 - 33
src/CBD/preprocessing/test.dot

@@ -1,37 +1,17 @@
 
 digraph graphname {
- h [label="InputPortBlock (h)"];
-t [label="InputPortBlock (t)"];
-k_1 [label="InputPortBlock (k_1)"];
-IN1mult [label="InputPortBlock (IN1-mult)"];
-IN2mult [label="InputPortBlock (IN2-mult)"];
-OUT1 [label="OutputPortBlock (OUT1)"];
-FMult -> OUT1 [label="IN1"];
-IVP0 [label="CBD (IVP-0)",shape=Msquare];
-CSum -> IVP0 [label="time"];
-YSumIN1mult -> IVP0 [label="IN1-mult"];
-YSumIN2mult -> IVP0 [label="IN2-mult"];
-C [label="ConstantBlock (C)\n1"];
-CMult [label="ProductBlock (CMult)"];
-h -> CMult [label="IN1"];
-C -> CMult [label="IN2"];
-CSum [label="AdderBlock (CSum)"];
-t -> CSum [label="IN1"];
-CMult -> CSum [label="IN2"];
-KSum [label="AdderBlock (KSum)"];
-Mult_1 -> KSum [label="IN1"];
-A_1 [label="ConstantBlock (A_1)\n1"];
-Mult_1 [label="ProductBlock (Mult_1)"];
-A_1 -> Mult_1 [label="IN1"];
-k_1 -> Mult_1 [label="IN2"];
-YSumIN1mult [label="AdderBlock (YSum-IN1-mult)"];
-IN1mult -> YSumIN1mult [label="IN1"];
-KSum -> YSumIN1mult [label="IN2"];
-YSumIN2mult [label="AdderBlock (YSum-IN2-mult)"];
-IN2mult -> YSumIN2mult [label="IN1"];
-KSum -> YSumIN2mult [label="IN2"];
-FMult [label="ProductBlock (FMult)"];
-h -> FMult [label="IN1"];
-IVP0 -> FMult [label="IN2"];
+ node_140435935930928 [label="InputPortBlock (time)"];
+node_140435935931024 [label="OutputPortBlock (OUT1)"];
+node_140435935930976 -> node_140435935931024 [label="IN1 / OUT1"];
+node_140435935930976 [label="AdderBlock (sum)"];
+node_140435935929104 -> node_140435935930976 [label="IN2 / OUT1"];
+node_140435935899712 -> node_140435935930976 [label="IN1 / OUT1"];
+node_140435935929104 [label="ProductBlock (mult)"];
+node_140435935901392 -> node_140435935929104 [label="IN1 / OUT1"];
+node_140435935901392 -> node_140435935929104 [label="IN2 / OUT2"];
+node_140435935899712 [label="ConstantBlock (one)\n1"];
+node_140435935901392 [label="SplitBlock (split)"];
+node_140435935931504 -> node_140435935901392 [label="IN1 / OUT1"];
+node_140435935931504 [label="InputPortBlock (IN1-split)"];
 
 }

+ 1 - 1
src/CBD/stepsize.py

@@ -262,7 +262,7 @@ class ButcherTableau:
 			raise ValueError("Trying to set weights on incomplete matrix")
 		if len(self._weights) == 2:
 			raise ValueError("Maximal amount of weight rows (2) reached")
-		if sum(weights) != 1:
+		if abs(sum(weights) - 1) > 1e-6:
 			raise ValueError("Inconsistent Butcher Tableau for Runge-Kutta approximation. "
 			                 "The sum of the weights must equal 1.")
 		self._weights.append(weights)