separate disjunct portions of circuit

This commit is contained in:
Patrick Haßel 2024-05-22 13:43:46 +02:00
parent 4a335353b9
commit a4d8f9cb2a
12 changed files with 117 additions and 72 deletions

View File

@ -10,8 +10,10 @@ import lombok.NonNull;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.linear.*; 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.List;
import java.util.Set;
import static java.lang.Math.max; import static java.lang.Math.max;
@ -19,11 +21,15 @@ import static java.lang.Math.max;
@Getter @Getter
public class Calculation { 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 static final double FULL_ADMITTANCE = 1 / NO_RESISTANCE;
private final List<Junction> junctions; private final List<Junction> junctions = new ArrayList<>();
private final Set<Part> parts = new HashSet<>();
private final Set<Wire> wires = new HashSet<>();
private final RealMatrix matrix; private final RealMatrix matrix;
@ -31,29 +37,49 @@ public class Calculation {
private RealVector potentials = null; private RealVector potentials = null;
public static List<Calculation> calculate(final Circuit circuit) {
final List<Calculation> calculations = new ArrayList<>();
final List<PartBattery> batteries = new ArrayList<>(circuit.streamParts().flatMap(PartBattery::filterCast).toList());
while (!batteries.isEmpty()) {
final PartBattery pivot = batteries.removeFirst();
final Set<Junction> 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) { public Calculation(final int numNodes) {
junctions = Collections.emptyList();
matrix = new Array2DRowRealMatrix(numNodes, numNodes); matrix = new Array2DRowRealMatrix(numNodes, numNodes);
currents = new ArrayRealVector(numNodes); currents = new ArrayRealVector(numNodes);
} }
public Calculation(final Circuit circuit) { private Calculation(final Set<Junction> connectedJunctions, final PartBattery pivot) {
final PartBattery pivot = circuit.streamParts().flatMap(PartBattery::filterCast).findFirst().orElseThrow(RuntimeException::new); for (final Junction junction : connectedJunctions) {
junctions = circuit.streamJunctions().filter(junction -> junction != pivot.getMinus()).toList(); // pivot.minus is GND and cannot be part of the matrix (linear dependency) parts.add(junction.getOwner());
matrix = new Array2DRowRealMatrix(junctions.size(), junctions.size()); if (!junctions.contains(junction) && junction != pivot.getMinus()) {
currents = new ArrayRealVector(junctions.size()); // pivot.minus is GND and cannot be part of the matrix (linear dependency)
fromSchematic(circuit); this.junctions.add(junction);
solve(); }
toSchematic(circuit); wires.addAll(junction.getWires());
} }
private void fromSchematic(final Circuit circuit) { matrix = new Array2DRowRealMatrix(this.junctions.size(), this.junctions.size());
circuit.streamWires().forEach( currents = new ArrayRealVector(this.junctions.size());
fromSchematic();
solve();
toSchematic();
}
private void fromSchematic() {
wires.forEach(
wire -> addResistor(wire.getA(), wire.getB(), NO_RESISTANCE) wire -> addResistor(wire.getA(), wire.getB(), NO_RESISTANCE)
); );
circuit.streamParts().forEach(part -> { parts.forEach(part -> {
for (final InnerConnection innerConnection : part.getInnerConnections()) { 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) { if (part instanceof final PartBattery battery) {
addBattery(battery); addBattery(battery);
@ -63,10 +89,12 @@ public class Calculation {
}); });
} }
private void toSchematic(final Circuit circuit) { private void toSchematic() {
circuit.streamJunctions().forEach(junction -> junction.setVoltage(getPotential(junction))); wires.forEach(wire -> wire.setCurrent(getCurrent(wire)));
circuit.streamWires().forEach(wire -> wire.setCurrent(getCurrent(wire))); parts.forEach(part -> {
circuit.streamParts().forEach(Part::postCalculate); part.getJunctions().forEach(junction -> junction.setVoltage(getPotential(junction)));
part.postCalculate();
});
} }
private double getPotential(final @NonNull Junction junction) { private double getPotential(final @NonNull Junction junction) {

View File

@ -17,8 +17,6 @@ public class Circuit {
private final List<Part> parts = new ArrayList<>(); private final List<Part> parts = new ArrayList<>();
private final List<Junction> junctions = new ArrayList<>();
private final List<Wire> wires = new ArrayList<>(); private final List<Wire> wires = new ArrayList<>();
public Circuit(final CircuitDto dto) { public Circuit(final CircuitDto dto) {
@ -42,7 +40,7 @@ public class Circuit {
} }
public void evaluateAndRender() { public void evaluateAndRender() {
new Calculation(this); Calculation.calculate(this);
parts.forEach(Part::render); parts.forEach(Part::render);
} }
@ -52,7 +50,6 @@ public class Circuit {
} }
if (isFree(part.getPosition())) { if (isFree(part.getPosition())) {
parts.add(part); parts.add(part);
junctions.addAll(part.getJunctions());
part.render(); part.render();
} }
return part; return part;
@ -75,10 +72,6 @@ public class Circuit {
return parts.stream(); return parts.stream();
} }
public Stream<Junction> streamJunctions() {
return junctions.stream();
}
public Stream<Wire> streamWires() { public Stream<Wire> streamWires() {
return wires.stream(); return wires.stream();
} }

View File

@ -17,19 +17,10 @@ public class CircuitPanel extends JPanel {
public CircuitPanel() { public CircuitPanel() {
new CircuitPanelDropTarget(this, circuit); new CircuitPanelDropTarget(this, circuit);
final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(1, 0))); final PartBattery battery = circuit.addPart(new PartBattery(Position.ofRaster(0, 0)));
final PartLight light = circuit.addPart(new PartLight(Position.ofRaster(0, 1)));
final PartLight light0 = circuit.addPart(new PartLight(Position.ofRaster(0, 2))); circuit.connect(battery.getMinus(), light.getA());
light0.clockwise(); circuit.connect(light.getB(), battery.getPlus());
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());
} }
@Override @Override

View File

@ -1,14 +1,28 @@
package de.ph87.electro.circuit.part; package de.ph87.electro.circuit.part;
import java.util.stream.Stream;
public class InnerConnection { public class InnerConnection {
public final Junction a; public final Junction a;
public final Junction b; 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.a = a;
this.b = b; this.b = b;
this.resistance = resistance;
}
public Stream<Junction> filter(final Junction junction) {
if (a == junction) {
return Stream.of(b);
} else if (b == junction) {
return Stream.of(a);
}
return Stream.empty();
} }
} }

View File

@ -74,4 +74,13 @@ public class Junction {
return this.position.distance(position) <= JUNCTION_RADIUS_HOVER; return this.position.distance(position) <= JUNCTION_RADIUS_HOVER;
} }
public void collectConnectedJunctions(final Set<Junction> 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));
}
} }

View File

@ -110,6 +110,10 @@ public abstract class Part {
// may be overwritten // may be overwritten
} }
public List<InnerConnection> getInnerConnections() {
return Collections.emptyList();
}
public static Part of(final PartDto abstractDto) { public static Part of(final PartDto abstractDto) {
return switch (abstractDto) { return switch (abstractDto) {
case final PartBatteryDto dto -> new PartBattery(dto); case final PartBatteryDto dto -> new PartBattery(dto);
@ -124,8 +128,4 @@ public abstract class Part {
}; };
} }
public List<InnerConnection> getInnerConnections() {
return Collections.emptyList();
}
} }

View File

@ -45,8 +45,8 @@ public class PartBattery extends Part {
public PartBattery(final Position position) { public PartBattery(final Position position) {
super("Batterie", position); super("Batterie", position);
minus = newJunction(this, "PLUS", P10, P50); minus = newJunction(this, "MINUS", P10, P50);
plus = newJunction(this, "MINUS", P90, P50); plus = newJunction(this, "PLUS", P90, P50);
} }
public PartBattery(final PartBatteryDto dto) { public PartBattery(final PartBatteryDto dto) {

View File

@ -1,13 +1,12 @@
package de.ph87.electro.circuit.part.parts; package de.ph87.electro.circuit.part.parts;
import de.ph87.electro.circuit.part.Junction; import de.ph87.electro.circuit.part.*;
import de.ph87.electro.circuit.part.Orientation;
import de.ph87.electro.circuit.part.PartOther;
import de.ph87.electro.circuit.part.Position;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import java.awt.*; import java.awt.*;
import java.util.Collections;
import java.util.List;
import static de.ph87.electro.CONFIG.*; import static de.ph87.electro.CONFIG.*;
import static java.lang.Math.abs; import static java.lang.Math.abs;
@ -115,4 +114,12 @@ public class PartLight extends PartOther {
} }
} }
@Override
public List<InnerConnection> getInnerConnections() {
if (defect) {
return Collections.emptyList();
}
return List.of(new InnerConnection(a, b, resistance));
}
} }

View File

@ -12,6 +12,7 @@ import java.awt.*;
import java.util.List; import java.util.List;
import static de.ph87.electro.CONFIG.*; import static de.ph87.electro.CONFIG.*;
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
@Getter @Getter
@ToString(callSuper = true) @ToString(callSuper = true)
@ -59,7 +60,7 @@ public class PartSwitch1x1 extends PartOther {
@Override @Override
public List<InnerConnection> getInnerConnections() { public List<InnerConnection> getInnerConnections() {
if (state) { if (state) {
return List.of(new InnerConnection(common, output)); return List.of(new InnerConnection(common, output, NO_RESISTANCE));
} }
return super.getInnerConnections(); return super.getInnerConnections();
} }

View File

@ -11,6 +11,7 @@ import lombok.ToString;
import java.util.List; import java.util.List;
import static de.ph87.electro.CONFIG.*; import static de.ph87.electro.CONFIG.*;
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
@Getter @Getter
@ToString(callSuper = true) @ToString(callSuper = true)
@ -61,9 +62,9 @@ public class PartSwitch1x2 extends PartOther {
@Override @Override
public List<InnerConnection> getInnerConnections() { public List<InnerConnection> getInnerConnections() {
if (state) { 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));
} }
} }

View File

@ -11,6 +11,7 @@ import lombok.ToString;
import java.util.List; import java.util.List;
import static de.ph87.electro.CONFIG.*; import static de.ph87.electro.CONFIG.*;
import static de.ph87.electro.circuit.Calculation.NO_RESISTANCE;
@Getter @Getter
@ToString(callSuper = true) @ToString(callSuper = true)
@ -68,13 +69,13 @@ public class PartSwitchCross extends PartOther {
public List<InnerConnection> getInnerConnections() { public List<InnerConnection> getInnerConnections() {
if (state) { if (state) {
return List.of( return List.of(
new InnerConnection(common0, output1), new InnerConnection(common0, output1, NO_RESISTANCE),
new InnerConnection(common1, output0) new InnerConnection(common1, output0, NO_RESISTANCE)
); );
} }
return List.of( return List.of(
new InnerConnection(common0, output0), new InnerConnection(common0, output0, NO_RESISTANCE),
new InnerConnection(common1, output1) new InnerConnection(common1, output1, NO_RESISTANCE)
); );
} }

View File

@ -20,8 +20,7 @@ class CalculationServiceTest {
circuit.connect(battery.getMinus(), light.getA()); circuit.connect(battery.getMinus(), light.getA());
circuit.connect(battery.getPlus(), light.getB()); circuit.connect(battery.getPlus(), light.getB());
final Calculation calculation = new Calculation(circuit); for (final Calculation calculation : Calculation.calculate(circuit)) {
calculation.toString().lines().forEach(log::info); calculation.toString().lines().forEach(log::info);
circuit.streamParts().forEach(part -> { circuit.streamParts().forEach(part -> {
log.info(""); log.info("");
@ -36,5 +35,6 @@ class CalculationServiceTest {
}); });
log.info(""); log.info("");
} }
}
} }