diff --git a/src/SpiceSharpParser.IntegrationTests/Components/SubcircuitTests.cs b/src/SpiceSharpParser.IntegrationTests/Components/SubcircuitTests.cs index 7b6d81c3..97503a73 100644 --- a/src/SpiceSharpParser.IntegrationTests/Components/SubcircuitTests.cs +++ b/src/SpiceSharpParser.IntegrationTests/Components/SubcircuitTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Xunit; namespace SpiceSharpParser.IntegrationTests.Components @@ -455,5 +456,48 @@ public void SubcircuitWithWrongEnding() var model = parser.ParseNetlist(text); Assert.True(model.ValidationResult.HasError); } + + [Fact] + public void When_GND_Port_Used_In_Behavioral_Source_With_Tran() + { + // Regression test: SUBCKT with GND port name + behavioral source + // must work in .TRAN, not just .OP. Previously, Generate() bypassed + // the pin map for "GND", creating a floating node instead of mapping + // to the external ground node "0". + var model = GetSpiceSharpModel( + "Subcircuit GND Port TRAN Test", + "V1 IN 0 4.0", + "X1 0 IN OUT test_subckt", + ".SUBCKT test_subckt GND INPUT OUTPUT", + "R1 INPUT mid 5k", + "R2 mid GND 5k", + "B1 OUTPUT GND V={0.5 * V(INPUT,GND)}", + ".ENDS test_subckt", + ".TRAN 1u 100u", + ".SAVE V(OUT)", + ".END"); + + var simulations = model.Simulations; + Assert.Single(simulations); + + var tran = simulations[0]; + double lastValue = double.NaN; + + tran.EventExportData += (sender, e) => + { + var exports = model.Exports.Where(ex => ex.Simulation == tran).ToList(); + foreach (var export in exports) + { + lastValue = export.Extract(); + } + }; + + var codes = tran.Run(model.Circuit, -1); + codes = tran.InvokeEvents(codes); + codes.ToArray(); + + // B1 = 0.5 * V(IN,0) = 0.5 * 4.0 = 2.0V + Assert.InRange(lastValue, 1.9, 2.1); + } } } \ No newline at end of file diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Names/SubcircuitNodeNameGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Names/SubcircuitNodeNameGenerator.cs index 07e891b2..cc91f093 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Names/SubcircuitNodeNameGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Names/SubcircuitNodeNameGenerator.cs @@ -108,6 +108,17 @@ public string Generate(string nodeName) throw new ArgumentNullException(nameof(nodeName)); } + // Pin map takes priority — subcircuit port mapping must override + // the GND alias below, otherwise a port named "GND" mapped to + // external "0" would create a floating node instead of connecting + // to the real ground. + var pinIdentifier = nodeName; + + if (_pinMap.ContainsKey(pinIdentifier)) + { + return _pinMap[pinIdentifier]; + } + if (nodeName.ToUpper() == "GND") { return nodeName; @@ -118,16 +129,7 @@ public string Generate(string nodeName) return nodeName; } - var pinIdentifier = nodeName; - - if (_pinMap.ContainsKey(pinIdentifier)) - { - return _pinMap[pinIdentifier]; - } - else - { - return $"{SubCircuitFullName}{Separator}{nodeName}"; - } + return $"{SubCircuitFullName}{Separator}{nodeName}"; } /// diff --git a/src/SpiceSharpParser/SpiceSharpParser.csproj b/src/SpiceSharpParser/SpiceSharpParser.csproj index 541b5630..4da60a38 100644 --- a/src/SpiceSharpParser/SpiceSharpParser.csproj +++ b/src/SpiceSharpParser/SpiceSharpParser.csproj @@ -22,7 +22,7 @@ MIT latest - 3.2.11 + 3.2.12