From a4d8f9cb2ad8ecb86e67a34325c2e89c64b81ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Wed, 22 May 2024 13:43:46 +0200 Subject: [PATCH] separate disjunct portions of circuit --- .../de/ph87/electro/circuit/Calculation.java | 66 +++++++++++++------ .../java/de/ph87/electro/circuit/Circuit.java | 9 +-- .../de/ph87/electro/circuit/CircuitPanel.java | 17 ++--- .../electro/circuit/part/InnerConnection.java | 16 ++++- .../ph87/electro/circuit/part/Junction.java | 9 +++ .../de/ph87/electro/circuit/part/Part.java | 8 +-- .../circuit/part/parts/PartBattery.java | 4 +- .../electro/circuit/part/parts/PartLight.java | 15 +++-- .../circuit/part/parts/PartSwitch1x1.java | 3 +- .../circuit/part/parts/PartSwitch1x2.java | 5 +- .../circuit/part/parts/PartSwitchCross.java | 9 +-- .../circuit/net/CalculationServiceTest.java | 28 ++++---- 12 files changed, 117 insertions(+), 72 deletions(-) diff --git a/src/main/java/de/ph87/electro/circuit/Calculation.java b/src/main/java/de/ph87/electro/circuit/Calculation.java index 252131e..862c127 100644 --- a/src/main/java/de/ph87/electro/circuit/Calculation.java +++ b/src/main/java/de/ph87/electro/circuit/Calculation.java @@ -10,8 +10,10 @@ import lombok.NonNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.math3.linear.*; -import java.util.Collections; +import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static java.lang.Math.max; @@ -19,11 +21,15 @@ import static java.lang.Math.max; @Getter public class Calculation { - private static final double NO_RESISTANCE = 1e-12; + public static final double NO_RESISTANCE = 1e-12; private static final double FULL_ADMITTANCE = 1 / NO_RESISTANCE; - private final List junctions; + private final List junctions = new ArrayList<>(); + + private final Set parts = new HashSet<>(); + + private final Set wires = new HashSet<>(); private final RealMatrix matrix; @@ -31,29 +37,49 @@ public class Calculation { private RealVector potentials = null; + public static List calculate(final Circuit circuit) { + final List calculations = new ArrayList<>(); + final List batteries = new ArrayList<>(circuit.streamParts().flatMap(PartBattery::filterCast).toList()); + while (!batteries.isEmpty()) { + final PartBattery pivot = batteries.removeFirst(); + final Set connectedJunctions = new HashSet<>(); + pivot.getPlus().collectConnectedJunctions(connectedJunctions); + pivot.getMinus().collectConnectedJunctions(connectedJunctions); + connectedJunctions.stream().map(Junction::getOwner).flatMap(PartBattery::filterCast).forEach(batteries::remove); + calculations.add(new Calculation(connectedJunctions, pivot)); + } + return calculations; + } + public Calculation(final int numNodes) { - junctions = Collections.emptyList(); matrix = new Array2DRowRealMatrix(numNodes, numNodes); currents = new ArrayRealVector(numNodes); } - public Calculation(final Circuit circuit) { - final PartBattery pivot = circuit.streamParts().flatMap(PartBattery::filterCast).findFirst().orElseThrow(RuntimeException::new); - junctions = circuit.streamJunctions().filter(junction -> junction != pivot.getMinus()).toList(); // pivot.minus is GND and cannot be part of the matrix (linear dependency) - matrix = new Array2DRowRealMatrix(junctions.size(), junctions.size()); - currents = new ArrayRealVector(junctions.size()); - fromSchematic(circuit); + private Calculation(final Set connectedJunctions, final PartBattery pivot) { + for (final Junction junction : connectedJunctions) { + parts.add(junction.getOwner()); + if (!junctions.contains(junction) && junction != pivot.getMinus()) { + // pivot.minus is GND and cannot be part of the matrix (linear dependency) + this.junctions.add(junction); + } + wires.addAll(junction.getWires()); + } + + matrix = new Array2DRowRealMatrix(this.junctions.size(), this.junctions.size()); + currents = new ArrayRealVector(this.junctions.size()); + fromSchematic(); solve(); - toSchematic(circuit); + toSchematic(); } - private void fromSchematic(final Circuit circuit) { - circuit.streamWires().forEach( + private void fromSchematic() { + wires.forEach( wire -> addResistor(wire.getA(), wire.getB(), NO_RESISTANCE) ); - circuit.streamParts().forEach(part -> { + parts.forEach(part -> { for (final InnerConnection innerConnection : part.getInnerConnections()) { - addResistor(innerConnection.a, innerConnection.b, NO_RESISTANCE); + addResistor(innerConnection.a, innerConnection.b, innerConnection.resistance); } if (part instanceof final PartBattery battery) { addBattery(battery); @@ -63,10 +89,12 @@ public class Calculation { }); } - private void toSchematic(final Circuit circuit) { - circuit.streamJunctions().forEach(junction -> junction.setVoltage(getPotential(junction))); - circuit.streamWires().forEach(wire -> wire.setCurrent(getCurrent(wire))); - circuit.streamParts().forEach(Part::postCalculate); + private void toSchematic() { + wires.forEach(wire -> wire.setCurrent(getCurrent(wire))); + parts.forEach(part -> { + part.getJunctions().forEach(junction -> junction.setVoltage(getPotential(junction))); + part.postCalculate(); + }); } private double getPotential(final @NonNull Junction junction) { diff --git a/src/main/java/de/ph87/electro/circuit/Circuit.java b/src/main/java/de/ph87/electro/circuit/Circuit.java index b3921c3..419f4a0 100644 --- a/src/main/java/de/ph87/electro/circuit/Circuit.java +++ b/src/main/java/de/ph87/electro/circuit/Circuit.java @@ -17,8 +17,6 @@ public class Circuit { private final List parts = new ArrayList<>(); - private final List junctions = new ArrayList<>(); - private final List wires = new ArrayList<>(); public Circuit(final CircuitDto dto) { @@ -42,7 +40,7 @@ public class Circuit { } public void evaluateAndRender() { - new Calculation(this); + Calculation.calculate(this); parts.forEach(Part::render); } @@ -52,7 +50,6 @@ public class Circuit { } if (isFree(part.getPosition())) { parts.add(part); - junctions.addAll(part.getJunctions()); part.render(); } return part; @@ -75,10 +72,6 @@ public class Circuit { return parts.stream(); } - public Stream streamJunctions() { - return junctions.stream(); - } - public Stream streamWires() { return wires.stream(); } diff --git a/src/main/java/de/ph87/electro/circuit/CircuitPanel.java b/src/main/java/de/ph87/electro/circuit/CircuitPanel.java index 2e27cdf..7a7a5e6 100644 --- a/src/main/java/de/ph87/electro/circuit/CircuitPanel.java +++ b/src/main/java/de/ph87/electro/circuit/CircuitPanel.java @@ -17,19 +17,10 @@ public class CircuitPanel extends JPanel { public CircuitPanel() { new CircuitPanelDropTarget(this, circuit); - final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(1, 0))); - - final PartLight light0 = circuit.addPart(new PartLight(Position.ofRaster(0, 2))); - light0.clockwise(); - - final PartLight light1 = circuit.addPart(new PartLight(Position.ofRaster(1, 2))); - light1.clockwise(); - light1.clockwise(); - light1.clockwise(); - - circuit.connect(battery.getMinus(), light0.getA()); - circuit.connect(light0.getB(), light1.getA()); - circuit.connect(light1.getB(), battery.getPlus()); + final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(0, 0))); + final PartLight light = circuit.addPart(new PartLight(Position.ofRaster(0, 1))); + circuit.connect(battery.getMinus(), light.getA()); + circuit.connect(light.getB(), battery.getPlus()); } @Override diff --git a/src/main/java/de/ph87/electro/circuit/part/InnerConnection.java b/src/main/java/de/ph87/electro/circuit/part/InnerConnection.java index b678a1d..152fc55 100644 --- a/src/main/java/de/ph87/electro/circuit/part/InnerConnection.java +++ b/src/main/java/de/ph87/electro/circuit/part/InnerConnection.java @@ -1,14 +1,28 @@ package de.ph87.electro.circuit.part; +import java.util.stream.Stream; + public class InnerConnection { public final Junction a; public final Junction b; - public InnerConnection(final Junction a, final Junction b) { + public final double resistance; + + public InnerConnection(final Junction a, final Junction b, final double resistance) { this.a = a; this.b = b; + this.resistance = resistance; + } + + public Stream filter(final Junction junction) { + if (a == junction) { + return Stream.of(b); + } else if (b == junction) { + return Stream.of(a); + } + return Stream.empty(); } } diff --git a/src/main/java/de/ph87/electro/circuit/part/Junction.java b/src/main/java/de/ph87/electro/circuit/part/Junction.java index b9cf002..351ce7a 100644 --- a/src/main/java/de/ph87/electro/circuit/part/Junction.java +++ b/src/main/java/de/ph87/electro/circuit/part/Junction.java @@ -74,4 +74,13 @@ public class Junction { return this.position.distance(position) <= JUNCTION_RADIUS_HOVER; } + public void collectConnectedJunctions(final Set connected) { + if (connected.contains(this)) { + return; + } + connected.add(this); + wires.forEach(wire -> wire.getOpposite(this).collectConnectedJunctions(connected)); + owner.getInnerConnections().stream().flatMap(innerConnection -> innerConnection.filter(this)).forEach(opposite -> opposite.collectConnectedJunctions(connected)); + } + } diff --git a/src/main/java/de/ph87/electro/circuit/part/Part.java b/src/main/java/de/ph87/electro/circuit/part/Part.java index b875772..1d00cfd 100644 --- a/src/main/java/de/ph87/electro/circuit/part/Part.java +++ b/src/main/java/de/ph87/electro/circuit/part/Part.java @@ -110,6 +110,10 @@ public abstract class Part { // may be overwritten } + public List getInnerConnections() { + return Collections.emptyList(); + } + public static Part of(final PartDto abstractDto) { return switch (abstractDto) { case final PartBatteryDto dto -> new PartBattery(dto); @@ -124,8 +128,4 @@ public abstract class Part { }; } - public List getInnerConnections() { - return Collections.emptyList(); - } - } diff --git a/src/main/java/de/ph87/electro/circuit/part/parts/PartBattery.java b/src/main/java/de/ph87/electro/circuit/part/parts/PartBattery.java index f2f4e58..9267212 100644 --- a/src/main/java/de/ph87/electro/circuit/part/parts/PartBattery.java +++ b/src/main/java/de/ph87/electro/circuit/part/parts/PartBattery.java @@ -45,8 +45,8 @@ public class PartBattery extends Part { public PartBattery(final Position position) { super("Batterie", position); - minus = newJunction(this, "PLUS", P10, P50); - plus = newJunction(this, "MINUS", P90, P50); + minus = newJunction(this, "MINUS", P10, P50); + plus = newJunction(this, "PLUS", P90, P50); } public PartBattery(final PartBatteryDto dto) { diff --git a/src/main/java/de/ph87/electro/circuit/part/parts/PartLight.java b/src/main/java/de/ph87/electro/circuit/part/parts/PartLight.java index 83ca3b4..386b923 100644 --- a/src/main/java/de/ph87/electro/circuit/part/parts/PartLight.java +++ b/src/main/java/de/ph87/electro/circuit/part/parts/PartLight.java @@ -1,13 +1,12 @@ package de.ph87.electro.circuit.part.parts; -import de.ph87.electro.circuit.part.Junction; -import de.ph87.electro.circuit.part.Orientation; -import de.ph87.electro.circuit.part.PartOther; -import de.ph87.electro.circuit.part.Position; +import de.ph87.electro.circuit.part.*; import lombok.Getter; import lombok.ToString; import java.awt.*; +import java.util.Collections; +import java.util.List; import static de.ph87.electro.CONFIG.*; import static java.lang.Math.abs; @@ -115,4 +114,12 @@ public class PartLight extends PartOther { } } + @Override + public List getInnerConnections() { + if (defect) { + return Collections.emptyList(); + } + return List.of(new InnerConnection(a, b, resistance)); + } + } diff --git a/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x1.java b/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x1.java index 9868f2b..8c4f7a3 100644 --- a/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x1.java +++ b/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x1.java @@ -12,6 +12,7 @@ import java.awt.*; import java.util.List; import static de.ph87.electro.CONFIG.*; +import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE; @Getter @ToString(callSuper = true) @@ -59,7 +60,7 @@ public class PartSwitch1x1 extends PartOther { @Override public List getInnerConnections() { if (state) { - return List.of(new InnerConnection(common, output)); + return List.of(new InnerConnection(common, output, NO_RESISTANCE)); } return super.getInnerConnections(); } diff --git a/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x2.java b/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x2.java index fbbff21..9fb6358 100644 --- a/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x2.java +++ b/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitch1x2.java @@ -11,6 +11,7 @@ import lombok.ToString; import java.util.List; import static de.ph87.electro.CONFIG.*; +import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE; @Getter @ToString(callSuper = true) @@ -61,9 +62,9 @@ public class PartSwitch1x2 extends PartOther { @Override public List getInnerConnections() { if (state) { - return List.of(new InnerConnection(common, output1)); + return List.of(new InnerConnection(common, output1, NO_RESISTANCE)); } - return List.of(new InnerConnection(common, output0)); + return List.of(new InnerConnection(common, output0, NO_RESISTANCE)); } } diff --git a/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitchCross.java b/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitchCross.java index 78fbf76..32ea360 100644 --- a/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitchCross.java +++ b/src/main/java/de/ph87/electro/circuit/part/parts/PartSwitchCross.java @@ -11,6 +11,7 @@ import lombok.ToString; import java.util.List; import static de.ph87.electro.CONFIG.*; +import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE; @Getter @ToString(callSuper = true) @@ -68,13 +69,13 @@ public class PartSwitchCross extends PartOther { public List getInnerConnections() { if (state) { return List.of( - new InnerConnection(common0, output1), - new InnerConnection(common1, output0) + new InnerConnection(common0, output1, NO_RESISTANCE), + new InnerConnection(common1, output0, NO_RESISTANCE) ); } return List.of( - new InnerConnection(common0, output0), - new InnerConnection(common1, output1) + new InnerConnection(common0, output0, NO_RESISTANCE), + new InnerConnection(common1, output1, NO_RESISTANCE) ); } diff --git a/src/test/java/de/ph87/electro/circuit/net/CalculationServiceTest.java b/src/test/java/de/ph87/electro/circuit/net/CalculationServiceTest.java index 1b1e0bc..e87c6f7 100644 --- a/src/test/java/de/ph87/electro/circuit/net/CalculationServiceTest.java +++ b/src/test/java/de/ph87/electro/circuit/net/CalculationServiceTest.java @@ -20,21 +20,21 @@ class CalculationServiceTest { circuit.connect(battery.getMinus(), light.getA()); circuit.connect(battery.getPlus(), light.getB()); - final Calculation calculation = new Calculation(circuit); - - calculation.toString().lines().forEach(log::info); - circuit.streamParts().forEach(part -> { - log.info(""); - log.info(part.toString()); - for (final Junction junction : part.getJunctions()) { - log.info(" \"%s\" = %.2f V".formatted(junction.getName(), junction.getVoltage())); - for (final Wire wire : junction.getWires()) { - final Junction opposite = wire.getOpposite(junction); - log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(junction))); + for (final Calculation calculation : Calculation.calculate(circuit)) { + calculation.toString().lines().forEach(log::info); + circuit.streamParts().forEach(part -> { + log.info(""); + log.info(part.toString()); + for (final Junction junction : part.getJunctions()) { + log.info(" \"%s\" = %.2f V".formatted(junction.getName(), junction.getVoltage())); + for (final Wire wire : junction.getWires()) { + final Junction opposite = wire.getOpposite(junction); + log.info(" -> %s.%s = %.2f A".formatted(opposite.getOwner().getName(), opposite.getName(), wire.getCurrent(junction))); + } } - } - }); - log.info(""); + }); + log.info(""); + } } }