diff --git a/src/SpiceSharpParser.IntegrationTests/Examples/Example01.cs b/src/SpiceSharpParser.IntegrationTests/Examples/Example01.cs new file mode 100644 index 00000000..5776ac47 --- /dev/null +++ b/src/SpiceSharpParser.IntegrationTests/Examples/Example01.cs @@ -0,0 +1,26 @@ +using System.IO; +using Xunit; + +namespace SpiceSharpParser.IntegrationTests.Examples +{ + public class Example01 : BaseTests + { + [Fact] + public void When_Simulated_Expect_NoExceptions() + { + string path = Path.Combine(Directory.GetCurrentDirectory(), "Resources/example01.cir"); + var netlistContent = File.ReadAllText(path); + + var parser = new SpiceParser(); + parser.Settings.Lexing.HasTitle = true; + + var parseResult = parser.ParseNetlist(netlistContent); + + double[] exports = RunOpSimulation(parseResult.SpiceSharpModel, new [] { "V(N1)", "V(N2)", "V(N3)" }); + + EqualsWithTol(1.0970919064909939, exports[0]); + EqualsWithTol(0.014696545624995935, exports[1]); + EqualsWithTol(0.014715219080886419, exports[2]); + } + } +} diff --git a/src/SpiceSharpParser.IntegrationTests/Resources/example01.cir b/src/SpiceSharpParser.IntegrationTests/Resources/example01.cir new file mode 100644 index 00000000..2868a67f --- /dev/null +++ b/src/SpiceSharpParser.IntegrationTests/Resources/example01.cir @@ -0,0 +1,45 @@ +Example 01 + +.param a0_entry=0.1 +.param b0_entry=0.01 +.param density =850 +.param viscosity =0.000006 +.param rout_entry =0.9 +.param rin_entry =0.8 +.param r1_entry1 =0.8 +.param r2_entry1=0.81 +.param r1_entry2 =0.89 +.param r2_entry2=0.9 +.param FlowRate =0.025 + +I_M 0 N1 {FlowRate} + +X_entry1 N1 0 N2 entry params: a0={a0_entry}, b0={b0_entry}, ro={density}, v={viscosity}, rout={rout_entry}, ++rin={rin_entry},r1={r1_entry1},r2={r2_entry1} + +X_entry2 N1 0 N3 entry params: a0={a0_entry}, b0={b0_entry}, ro={density}, v={viscosity}, rout={rout_entry}, ++rin={rin_entry},r1={r1_entry2},r2={r2_entry2} + +.subckt entry m_in m_out v_vel params: a0=1, b0=1, ro=1, v=1, rout=1, rin=1, r1=1, r2=1 +.param D0 = {2*a0*b0/(a0+b0)} +.param F1 = {(rout-rin)*a0*(rout+rin)/(r2+r1)} +.param F0 = {(r2-r1)*a0} +.param fraction = {F0/F1} +.func Q(m) {m/ro} +.func vel(m) {Q(m)/(a0*b0)} +.func R(x) {x*D0/v} +*Changed function +.func xi(x) {40*pow(R(x),-0.9) + 90*pow(fraction,-0.003)-80} +Vmas m_in msx {0} +Rmas msx msy 1e-6 +*The pressure drop: +Exm msy m_out value={xi(V(v_vel))*ro*V(v_vel)*V(v_vel)/2} +Hmss mss 0 Vmas 1 +*Velocity: +Guv 0 v_vel value={vel(V(mss))} +Ruv 0 v_vel 1 +.ends + +.OP +.SAVE V(N1) V(N2) V(N3) +.end \ No newline at end of file diff --git a/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj b/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj index 0c191a18..1dbef3d2 100644 --- a/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj +++ b/src/SpiceSharpParser.IntegrationTests/SpiceSharpParser.IntegrationTests.csproj @@ -12,6 +12,10 @@ true + + + + @@ -29,6 +33,9 @@ + + Always + Always diff --git a/src/SpiceSharpParser.PerformanceTests/ExpressionTests.cs b/src/SpiceSharpParser.PerformanceTests/ExpressionTests.cs index 5942ee47..1708e052 100644 --- a/src/SpiceSharpParser.PerformanceTests/ExpressionTests.cs +++ b/src/SpiceSharpParser.PerformanceTests/ExpressionTests.cs @@ -32,14 +32,16 @@ public void EvaluateDouble() var randomizer = new Randomizer(); for (var i = 0; i < n; i++) { - sum += expressionParser.EvaluateValueExpression( + sum += expressionParser.Evaluate( "1 + 1 + 1 + 1 + 1 + 1 + 1", new ExpressionContext( string.Empty, false, false, false, - randomizer)); + randomizer), + null, + null); } } } diff --git a/src/SpiceSharpParser.Tests/Common/Evaluation/ExpressionRegistryTests.cs b/src/SpiceSharpParser.Tests/Common/Evaluation/ExpressionRegistryTests.cs index 7a3fed6e..f8e9ccb1 100644 --- a/src/SpiceSharpParser.Tests/Common/Evaluation/ExpressionRegistryTests.cs +++ b/src/SpiceSharpParser.Tests/Common/Evaluation/ExpressionRegistryTests.cs @@ -2,6 +2,8 @@ using SpiceSharpParser.Common.Evaluation; using SpiceSharpParser.Common.Evaluation.Expressions; using System.Linq; +using SpiceSharp.Simulations; +using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using Xunit; namespace SpiceSharpParser.Tests.Common.Evaluation @@ -13,7 +15,7 @@ public void AddExpressionWithoutParameters() { var registry = new ExpressionRegistry(false, false); var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression(Arg.Any(), Arg.Any()).Returns(1); + evaluator.Evaluate(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()).Returns(1); registry.Add(new NamedExpression("test", "1"), new System.Collections.Generic.List()); @@ -24,7 +26,7 @@ public void AddExpressionWithoutParameters() public void AddExpressionWithParameters() { var registry = new ExpressionRegistry(false, false); - registry.Add(new Expression("x+1"), new System.Collections.Generic.List() { "x" }); + registry.Add(new DynamicExpression("x+1"), new System.Collections.Generic.List() { "x" }); Assert.Single(registry.GetDependentExpressions("x")); } @@ -33,9 +35,9 @@ public void AddExpressionWithParameters() public void AddExpressionsWithSingleParameter() { var registry = new ExpressionRegistry(false, false); - registry.Add(new Expression("x+1"), new System.Collections.Generic.List() { "x" }); - registry.Add(new Expression("y+1"), new System.Collections.Generic.List() { "y" }); - registry.Add(new Expression("x+1"), new System.Collections.Generic.List() { "x" }); + registry.Add(new DynamicExpression("x+1"), new System.Collections.Generic.List() { "x" }); + registry.Add(new DynamicExpression("y+1"), new System.Collections.Generic.List() { "y" }); + registry.Add(new DynamicExpression("x+1"), new System.Collections.Generic.List() { "x" }); Assert.Single(registry.GetDependentExpressions("y")); Assert.Equal(2, registry.GetDependentExpressions("x").Count()); @@ -45,9 +47,9 @@ public void AddExpressionsWithSingleParameter() public void AddExpressionsWithMultipleParameter() { var registry = new ExpressionRegistry(false, false); - registry.Add(new Expression("x+y+1"), new System.Collections.Generic.List() { "x", "y" }); - registry.Add(new Expression("y+x+1"), new System.Collections.Generic.List() { "y", "x" }); - registry.Add(new Expression("x+1"), new System.Collections.Generic.List() { "x" }); + registry.Add(new DynamicExpression("x+y+1"), new System.Collections.Generic.List() { "x", "y" }); + registry.Add(new DynamicExpression("y+x+1"), new System.Collections.Generic.List() { "y", "x" }); + registry.Add(new DynamicExpression("x+1"), new System.Collections.Generic.List() { "x" }); Assert.Equal(2, registry.GetDependentExpressions("y").Count()); Assert.Equal(3, registry.GetDependentExpressions("x").Count()); diff --git a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Evaluation/SpiceEvaluatorTests.cs b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Evaluation/SpiceEvaluatorTests.cs index 1cf29243..59740fcd 100644 --- a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Evaluation/SpiceEvaluatorTests.cs +++ b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Evaluation/SpiceEvaluatorTests.cs @@ -2,6 +2,7 @@ using SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation; using SpiceSharpParser.Parsers.Expression; using System; +using SpiceSharpParser.Common.Evaluation.Expressions; using Xunit; namespace SpiceSharpParser.Tests.ModelReaders.Spice.Evaluation @@ -20,11 +21,11 @@ public void ParentEvaluator() var v = c.CreateChildContext("child", false); v.SetParameter("xyz", 13.0); - Assert.Equal(1, v.Parameters["a"].CurrentValue); + Assert.Equal(1, ((ConstantExpression)v.Parameters["a"]).Value); v.SetParameter("a", 2); - Assert.Equal(2, v.Parameters["a"].CurrentValue); - Assert.Equal(1, c.Parameters["a"].CurrentValue); + Assert.Equal(2, ((ConstantExpression)v.Parameters["a"]).Value); + Assert.Equal(1, ((ConstantExpression)c.Parameters["a"]).Value); } [Fact] @@ -34,7 +35,7 @@ public void EvaluateParameter() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); c.SetParameter("xyz", 13.0); - Assert.Equal(14, v.EvaluateValueExpression("xyz + 1", c)); + Assert.Equal(14, v.Evaluate("xyz + 1", c, null, null)); } [Fact] @@ -42,7 +43,7 @@ public void EvaluateSuffix() { Evaluator v = new Evaluator(); var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); - Assert.Equal(2, v.EvaluateValueExpression("1V + 1", c)); + Assert.Equal(2, v.Evaluate("1V + 1", c, null, null)); } [Fact] @@ -51,7 +52,7 @@ public void TableBasic() Evaluator v = new Evaluator(); var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); c.SetParameter("N", 1.0); - Assert.Equal(10, v.EvaluateValueExpression("table(N, 1, pow(10, 1), 2 + 0, 20, 3, 30)", c)); + Assert.Equal(10, v.Evaluate("table(N, 1, pow(10, 1), 2 + 0, 20, 3, 30)", c, null, null)); } [Fact] @@ -61,16 +62,16 @@ public void TableInterpolation() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); c.SetParameter("N", 1.5); - Assert.Equal(-5, v.EvaluateValueExpression("table(N, 1, 0, 2, -10)", c)); + Assert.Equal(-5, v.Evaluate("table(N, 1, 0, 2, -10)", c, null, null)); c.SetParameter("N", 3); - Assert.Equal(-10, v.EvaluateValueExpression("table(N, 1, 0, 2, -10)", c)); + Assert.Equal(-10, v.Evaluate("table(N, 1, 0, 2, -10)", c, null, null)); c.SetParameter("N", 0); - Assert.Equal(0, v.EvaluateValueExpression("table(N, 1, 0, 2, -10)", c)); + Assert.Equal(0, v.Evaluate("table(N, 1, 0, 2, -10)", c, null, null)); c.SetParameter("N", -1); - Assert.Equal(0, v.EvaluateValueExpression("table(N, 1, 0, 2, -10)", c)); + Assert.Equal(0, v.Evaluate("table(N, 1, 0, 2, -10)", c, null, null)); } [Fact] @@ -79,7 +80,7 @@ public void TableAdvanced() Evaluator v = new Evaluator(); var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); c.SetParameter("N", 1.0); - Assert.Equal(10, v.EvaluateValueExpression("table(N, 1, pow(10, 1), 2 + 0, 20, 3, 30)", c)); + Assert.Equal(10, v.Evaluate("table(N, 1, pow(10, 1), 2 + 0, 20, 3, 30)", c, null, null)); } [Fact] @@ -89,19 +90,8 @@ public void Round() var evaluator = new Evaluator(); var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("round(1.2)", c)); - Assert.Equal(2, evaluator.EvaluateValueExpression("round(1.9)", c)); - } - - [Fact] - public void PowMinusLtSpice() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.LtSpice); - - // act and assert - Assert.Equal(0, evaluator.EvaluateValueExpression("pow(-2,1.5)", c)); + Assert.Equal(1, evaluator.Evaluate("round(1.2)", c, null, null)); + Assert.Equal(2, evaluator.Evaluate("round(1.9)", c, null, null)); } [Fact] @@ -112,7 +102,7 @@ public void PwrLtSpice() var c = new SpiceExpressionContext(SpiceExpressionMode.LtSpice); // act and assert - Assert.Equal(8, evaluator.EvaluateValueExpression("pwr(-2,3)", c)); + Assert.Equal(8, evaluator.Evaluate("pwr(-2,3)", c, null, null)); } [Fact] @@ -123,7 +113,7 @@ public void PwrHSpice() var c = new SpiceExpressionContext(SpiceExpressionMode.HSpice); // act and assert - Assert.Equal(-8, evaluator.EvaluateValueExpression("pwr(-2,3)", c)); + Assert.Equal(-8, evaluator.Evaluate("pwr(-2,3)", c, null, null)); } [Fact] @@ -134,28 +124,7 @@ public void PwrSmartSpice() var c = new SpiceExpressionContext(SpiceExpressionMode.SmartSpice); // act and assert - Assert.Equal(-8, evaluator.EvaluateValueExpression("pwr(-2,3)", c)); - } - - [Fact] - public void PowMinusSmartSpice() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.SmartSpice); - - // act and assert - Assert.Equal(Math.Pow(2, (int)1.5), evaluator.EvaluateValueExpression("pow(-2,1.5)", c)); - } - - [Fact] - public void PowMinusHSpice() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.HSpice); - // act and assert - Assert.Equal(Math.Pow(-2, (int)1.5), evaluator.EvaluateValueExpression("pow(-2,1.5)", c)); + Assert.Equal(-8, evaluator.Evaluate("pwr(-2,3)", c, null, null)); } [Fact] @@ -165,9 +134,9 @@ public void Sgn() var evaluator = new Evaluator(); var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(0, evaluator.EvaluateValueExpression("sgn(0)", c)); - Assert.Equal(-1, evaluator.EvaluateValueExpression("sgn(-1)", c)); - Assert.Equal(1, evaluator.EvaluateValueExpression("sgn(0.1)", c)); + Assert.Equal(0, evaluator.Evaluate("sgn(0)", c, null, null)); + Assert.Equal(-1, evaluator.Evaluate("sgn(-1)", c, null, null)); + Assert.Equal(1, evaluator.Evaluate("sgn(0.1)", c, null, null)); } [Fact] @@ -178,40 +147,7 @@ public void Sqrt() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(2, evaluator.EvaluateValueExpression("sqrt(4)", c)); - } - - [Fact] - public void SqrtMinusHSpice() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.HSpice); - - // act and assert - Assert.Equal(-2, evaluator.EvaluateValueExpression("sqrt(-4)", c)); - } - - [Fact] - public void SqrtMinusSmartSpice() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.SmartSpice); - - // act and assert - Assert.Equal(2, evaluator.EvaluateValueExpression("sqrt(-4)", c)); - } - - [Fact] - public void SqrtMinusLtSpice() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.LtSpice); - - // act and assert - Assert.Equal(0, evaluator.EvaluateValueExpression("sqrt(-4)", c)); + Assert.Equal(2, evaluator.Evaluate("sqrt(4)", c, null, null)); } [Fact] @@ -223,7 +159,7 @@ public void DefPositive() c.SetParameter("x1", 1); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("def(x1)", c)); + Assert.Equal(1, evaluator.Evaluate("def(x1)", c, null, null)); } [Fact] @@ -234,7 +170,7 @@ public void DefNegative() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(0, evaluator.EvaluateValueExpression("def(x1)", c)); + Assert.Equal(0, evaluator.Evaluate("def(x1)", c, null, null)); } [Fact] @@ -245,7 +181,7 @@ public void Abs() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("abs(-1)", c)); + Assert.Equal(1, evaluator.Evaluate("abs(-1)", c, null, null)); } [Fact] @@ -256,7 +192,7 @@ public void AGauss() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - evaluator.EvaluateValueExpression("agauss(0, 1, 2)", c); + evaluator.Evaluate("agauss(0, 1, 2)", c, null, null); } [Fact] @@ -267,7 +203,7 @@ public void AUnif() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - evaluator.EvaluateValueExpression("aunif(0, 1)", c); + evaluator.Evaluate("aunif(0, 1)", c, null, null); } [Fact] @@ -278,7 +214,7 @@ public void Unif() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - evaluator.EvaluateValueExpression("unif(1, 0.5)", c); + evaluator.Evaluate("unif(1, 0.5)", c, null, null); } [Fact] @@ -289,7 +225,7 @@ public void LimitRandom() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - evaluator.EvaluateValueExpression("limit(0, 1)", c); + evaluator.Evaluate("limit(0, 1)", c, null, null); } [Fact] @@ -300,8 +236,8 @@ public void Buf() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("buf(0.6)", c)); - Assert.Equal(0, evaluator.EvaluateValueExpression("buf(0.3)", c)); + Assert.Equal(1, evaluator.Evaluate("buf(0.6)", c, null, null)); + Assert.Equal(0, evaluator.Evaluate("buf(0.3)", c, null, null)); } [Fact] @@ -312,7 +248,7 @@ public void Cbrt() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(2, evaluator.EvaluateValueExpression("cbrt(8)", c)); + Assert.Equal(2, evaluator.Evaluate("cbrt(8)", c, null, null)); } [Fact] @@ -323,7 +259,7 @@ public void Ceil() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(3, evaluator.EvaluateValueExpression("ceil(2.9)", c)); + Assert.Equal(3, evaluator.Evaluate("ceil(2.9)", c, null, null)); } [Fact] @@ -334,7 +270,7 @@ public void DbSmartSpice() var c = new SpiceExpressionContext(SpiceExpressionMode.SmartSpice); // act and assert - Assert.Equal(20, evaluator.EvaluateValueExpression("db(-10)", c)); + Assert.Equal(20, evaluator.Evaluate("db(-10)", c, null, null)); } [Fact] @@ -345,7 +281,7 @@ public void Db() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(-20, evaluator.EvaluateValueExpression("db(-10)", c)); + Assert.Equal(-20, evaluator.Evaluate("db(-10)", c, null, null)); } [Fact] @@ -356,18 +292,7 @@ public void Exp() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(Math.Exp(2), evaluator.EvaluateValueExpression("exp(2)", c)); - } - - [Fact] - public void Fabs() - { - // arrange - var evaluator = new Evaluator(); - var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); - - // act and assert - Assert.Equal(3, evaluator.EvaluateValueExpression("fabs(-3)", c)); + Assert.Equal(Math.Exp(2), evaluator.Evaluate("exp(2)", c, null, null)); } [Fact] @@ -378,7 +303,7 @@ public void Flat() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act - var res = evaluator.EvaluateValueExpression("flat(10)", c); + var res = evaluator.Evaluate("flat(10)", c, null, null); // assert Assert.True(res >= -10 && res <= 10); @@ -392,7 +317,7 @@ public void Floor() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(2, evaluator.EvaluateValueExpression("floor(2.3)", c)); + Assert.Equal(2, evaluator.Evaluate("floor(2.3)", c, null, null)); } [Fact] @@ -403,7 +328,7 @@ public void Hypot() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(5, evaluator.EvaluateValueExpression("hypot(3,4)", c)); + Assert.Equal(5, evaluator.Evaluate("hypot(3,4)", c, null, null)); } [Fact] @@ -414,7 +339,7 @@ public void Gauss() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - evaluator.EvaluateValueExpression("gauss(1.2)", c); + evaluator.Evaluate("gauss(1.2)", c, null, null); } [Fact] @@ -425,7 +350,7 @@ public void ExtendedGauss() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - evaluator.EvaluateValueExpression("gauss(1, 2.3, 4.5)", c); + evaluator.Evaluate("gauss(1, 2.3, 4.5)", c, null, null); } [Fact] @@ -436,7 +361,7 @@ public void ExtendedGauss_TooManyArguments() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Throws(() => evaluator.EvaluateValueExpression("gauss(1, 2.3, 4.5, 0)", c)); + Assert.Throws(() => evaluator.Evaluate("gauss(1, 2.3, 4.5, 0)", c, null, null)); } [Fact] @@ -447,8 +372,8 @@ public void If() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(3, evaluator.EvaluateValueExpression("if(0.5, 2, 3)", c)); - Assert.Equal(2, evaluator.EvaluateValueExpression("if(0.6, 2, 3)", c)); + Assert.Equal(3, evaluator.Evaluate("if(0.5, 2, 3)", c, null, null)); + Assert.Equal(2, evaluator.Evaluate("if(0.6, 2, 3)", c, null, null)); } [Fact] @@ -459,7 +384,7 @@ public void Int() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("int(1.3)", c)); + Assert.Equal(1, evaluator.Evaluate("int(1.3)", c, null, null)); } [Fact] @@ -470,8 +395,8 @@ public void Inv() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(0, evaluator.EvaluateValueExpression("inv(0.51)", c)); - Assert.Equal(1, evaluator.EvaluateValueExpression("inv(0.5)", c)); + Assert.Equal(0, evaluator.Evaluate("inv(0.51)", c, null, null)); + Assert.Equal(1, evaluator.Evaluate("inv(0.5)", c, null, null)); } [Fact] @@ -482,7 +407,7 @@ public void Ln() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("ln(e)", c)); + Assert.Equal(1, evaluator.Evaluate("ln(e)", c, null, null)); } [Fact] @@ -493,9 +418,9 @@ public void Limit() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(8, evaluator.EvaluateValueExpression("limit(10, 1, 8)", c)); - Assert.Equal(1, evaluator.EvaluateValueExpression("limit(-1, 1, 8)", c)); - Assert.Equal(4, evaluator.EvaluateValueExpression("limit(4, 1, 8)", c)); + Assert.Equal(8, evaluator.Evaluate("limit(10, 1, 8)", c, null, null)); + Assert.Equal(1, evaluator.Evaluate("limit(-1, 1, 8)", c, null, null)); + Assert.Equal(4, evaluator.Evaluate("limit(4, 1, 8)", c, null, null)); } [Fact] @@ -506,7 +431,7 @@ public void Log() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("log(e)", c)); + Assert.Equal(1, evaluator.Evaluate("log(e)", c, null, null)); } [Fact] @@ -517,7 +442,7 @@ public void Log10() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("log10(10)", c)); + Assert.Equal(1, evaluator.Evaluate("log10(10)", c, null, null)); } [Fact] @@ -528,7 +453,7 @@ public void Max() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(100, evaluator.EvaluateValueExpression("max(10, -10, 1, 20, 100, 2)", c)); + Assert.Equal(100, evaluator.Evaluate("max(10, -10, 1, 20, 100, 2)", c, null, null)); } [Fact] @@ -539,7 +464,7 @@ public void Min() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(-10, evaluator.EvaluateValueExpression("min(10, -10, 1, 20, 100, 2)", c)); + Assert.Equal(-10, evaluator.Evaluate("min(10, -10, 1, 20, 100, 2)", c, null, null)); } [Fact] @@ -550,8 +475,8 @@ public void Nint() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1, evaluator.EvaluateValueExpression("nint(1.2)", c)); - Assert.Equal(2, evaluator.EvaluateValueExpression("nint(1.9)", c)); + Assert.Equal(1, evaluator.Evaluate("nint(1.2)", c, null, null)); + Assert.Equal(2, evaluator.Evaluate("nint(1.9)", c, null, null)); } [Fact] @@ -562,8 +487,8 @@ public void URamp() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(1.2, evaluator.EvaluateValueExpression("uramp(1.2)", c)); - Assert.Equal(0, evaluator.EvaluateValueExpression("uramp(-0.1)", c)); + Assert.Equal(1.2, evaluator.Evaluate("uramp(1.2)", c, null, null)); + Assert.Equal(0, evaluator.Evaluate("uramp(-0.1)", c, null, null)); } [Fact] @@ -573,8 +498,8 @@ public void U() var evaluator = new Evaluator(); var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); - Assert.Equal(1, evaluator.EvaluateValueExpression("u(1.2)", c)); - Assert.Equal(0, evaluator.EvaluateValueExpression("u(-1)", c)); + Assert.Equal(1, evaluator.Evaluate("u(1.2)", c, null, null)); + Assert.Equal(0, evaluator.Evaluate("u(-1)", c, null, null)); } [Fact] @@ -585,7 +510,7 @@ public void UnitInExpression() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); // act and assert - Assert.Equal(100 * 1000, evaluator.EvaluateValueExpression("300kHz/3", c)); + Assert.Equal(100 * 1000, evaluator.Evaluate("300kHz/3", c, null, null)); } [Fact] @@ -600,13 +525,13 @@ public void Fibonacci() new System.Collections.Generic.List() { "x" }, "x <= 0 ? 0 : (x == 1 ? 1 : (fib(x-1) + fib(x-2)))")); - Assert.Equal(0, p.EvaluateValueExpression("fib(0)", c)); - Assert.Equal(1, p.EvaluateValueExpression("fib(1)", c)); - Assert.Equal(1, p.EvaluateValueExpression("fib(2)", c)); - Assert.Equal(2, p.EvaluateValueExpression("fib(3)", c)); - Assert.Equal(3, p.EvaluateValueExpression("fib(4)", c)); - Assert.Equal(5, p.EvaluateValueExpression("fib(5)", c)); - Assert.Equal(8, p.EvaluateValueExpression("fib(6)", c)); + Assert.Equal(0, p.Evaluate("fib(0)", c, null, null)); + Assert.Equal(1, p.Evaluate("fib(1)", c, null, null)); + Assert.Equal(1, p.Evaluate("fib(2)", c, null, null)); + Assert.Equal(2, p.Evaluate("fib(3)", c, null, null)); + Assert.Equal(3, p.Evaluate("fib(4)", c, null, null)); + Assert.Equal(5, p.Evaluate("fib(5)", c, null, null)); + Assert.Equal(8, p.Evaluate("fib(6)", c, null, null)); } [Fact] @@ -614,7 +539,7 @@ public void PolyThreeVariablesSum() { var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); - Assert.Equal(15, p.EvaluateValueExpression("poly(3, 3, 5, 7, 0, 1, 1, 1)", c)); + Assert.Equal(15, p.Evaluate("poly(3, 3, 5, 7, 0, 1, 1, 1)", c, null, null)); } [Fact] @@ -622,7 +547,7 @@ public void PolyTwoVariablesSum() { var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); - Assert.Equal(3, p.EvaluateValueExpression("poly(2, 1, 2, 0, 1, 1)", c)); + Assert.Equal(3, p.Evaluate("poly(2, 1, 2, 0, 1, 1)", c, null, null)); } [Fact] @@ -631,7 +556,7 @@ public void PolyTwoVariablesMult() var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); var context = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); - Assert.Equal(6, p.EvaluateValueExpression("poly(2, 3, 2, 0, 0, 0, 0, 1)", c)); + Assert.Equal(6, p.Evaluate("poly(2, 3, 2, 0, 0, 0, 0, 1)", c, null, null)); } [Fact] @@ -639,7 +564,7 @@ public void PolyOneVariableSquare() { var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); - Assert.Equal(4, p.EvaluateValueExpression("poly(1, 2, 0, 0, 1)", c)); + Assert.Equal(4, p.Evaluate("poly(1, 2, 0, 0, 1)", c, null, null)); } [Fact] @@ -647,7 +572,7 @@ public void PolyOneVariablePowerOfThree() { var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); - Assert.Equal(8, p.EvaluateValueExpression("poly(1, 2, 0, 0, 0, 1)", c)); + Assert.Equal(8, p.Evaluate("poly(1, 2, 0, 0, 0, 1)", c, null, null)); } [Fact] @@ -655,7 +580,7 @@ public void PolyOneVariableMultiple() { var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); - Assert.Equal(4, p.EvaluateValueExpression("poly(1, 2, 0, 2)", c)); + Assert.Equal(4, p.Evaluate("poly(1, 2, 0, 2)", c, null, null)); } [Fact] @@ -663,7 +588,7 @@ public void PolyOneVariableSquerePlusConstant() { var c = new SpiceExpressionContext(SpiceExpressionMode.Spice3f5); var p = new Evaluator(); - Assert.Equal(14, p.EvaluateValueExpression("poly(1, 2, 10, 0, 1)", c)); + Assert.Equal(14, p.Evaluate("poly(1, 2, 10, 0, 1)", c, null, null)); } } } diff --git a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/OptionTests.cs b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/OptionTests.cs index 234dd601..05a84458 100644 --- a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/OptionTests.cs +++ b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/OptionTests.cs @@ -5,12 +5,14 @@ using Xunit; using SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.Controls; using SpiceSharp; +using SpiceSharp.Simulations; using SpiceSharpParser.ModelReaders.Netlist.Spice; using SpiceSharpParser.Common.Evaluation; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Names; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Updates; using SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation; - +using SpiceSharpParser.Common.Evaluation.Expressions; + namespace SpiceSharpParser.Tests.ModelReaders.Spice.Readers.Controls.Simulations { public class OptionTests @@ -38,8 +40,8 @@ public void Read() }; var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression("12.2", Arg.Any()).Returns(12.2); - evaluator.EvaluateValueExpression("12.3", Arg.Any()).Returns(12.3); + evaluator.Evaluate(new ConstantExpression(12.2), Arg.Any(), Arg.Any(), Arg.Any()).Returns(12.2); + evaluator.Evaluate(new ConstantExpression(12.3), Arg.Any(), Arg.Any(), Arg.Any()).Returns(12.3); var resultService = new ResultService(new SpiceNetlistReaderResult(new Circuit(), "title")); var readingContext = new ReadingContext( diff --git a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/StTests.cs b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/StTests.cs index a459557d..c84252db 100644 --- a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/StTests.cs +++ b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/Controls/StTests.cs @@ -8,6 +8,7 @@ using SpiceSharp.Simulations; using SpiceSharpParser.ModelReaders.Netlist.Spice; using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Names; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Sweeps; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Updates; @@ -34,8 +35,8 @@ public void LinDefault() }; var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression("1", Arg.Any()).Returns(1.0); - evaluator.EvaluateValueExpression("5", Arg.Any()).Returns(5.0); + evaluator.Evaluate(new ConstantExpression(1), Arg.Any(), Arg.Any(), Arg.Any()).Returns(1.0); + evaluator.Evaluate(new ConstantExpression(5), Arg.Any(), Arg.Any(), Arg.Any()).Returns(5.0); var resultService = new ResultService( new SpiceNetlistReaderResult(new SpiceSharp.Circuit(), "title")); @@ -90,8 +91,8 @@ public void Lin() }; var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression("1", Arg.Any()).Returns(1.0); - evaluator.EvaluateValueExpression("5", Arg.Any()).Returns(5.0); + evaluator.Evaluate(new ConstantExpression(1.0), Arg.Any(), Arg.Any(), Arg.Any()).Returns(1.0); + evaluator.Evaluate(new ConstantExpression(5), Arg.Any(), Arg.Any(), Arg.Any()).Returns(5.0); var resultService = new ResultService( new SpiceNetlistReaderResult(new SpiceSharp.Circuit(), "title")); @@ -146,8 +147,8 @@ public void Dec() }; var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression("1", Arg.Any()).Returns(1.0); - evaluator.EvaluateValueExpression("16", Arg.Any()).Returns(16); + evaluator.Evaluate(new ConstantExpression(1), Arg.Any(), Arg.Any(), Arg.Any()).Returns(1.0); + evaluator.Evaluate(new ConstantExpression(16.0), Arg.Any(), Arg.Any(), Arg.Any()).Returns(16); var resultService = new ResultService( new SpiceNetlistReaderResult(new SpiceSharp.Circuit(), "title")); @@ -202,8 +203,8 @@ public void Oct() }; var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression("1", Arg.Any()).Returns(1.0); - evaluator.EvaluateValueExpression("16", Arg.Any()).Returns(16); + evaluator.Evaluate(new ConstantExpression(1.0), Arg.Any(), Arg.Any(), Arg.Any()).Returns(1.0); + evaluator.Evaluate(new ConstantExpression(16), Arg.Any(), Arg.Any(), Arg.Any()).Returns(16); var resultService = new ResultService( new SpiceNetlistReaderResult(new SpiceSharp.Circuit(), "title")); @@ -258,7 +259,7 @@ public void List() }; var evaluator = Substitute.For(); - evaluator.EvaluateValueExpression("1.0", Arg.Any()).Returns(1.0); + evaluator.Evaluate(new ConstantExpression(1.0), Arg.Any(), Arg.Any(), Arg.Any()).Returns(1.0); var resultService = new ResultService( new SpiceNetlistReaderResult(new SpiceSharp.Circuit(), "title")); diff --git a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/EntityGenerators/Components/RLCGeneratorTests.cs b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/EntityGenerators/Components/RLCGeneratorTests.cs index b2eefcc5..354f696b 100644 --- a/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/EntityGenerators/Components/RLCGeneratorTests.cs +++ b/src/SpiceSharpParser.Tests/ModelReaders/Spice/Readers/EntityGenerators/Components/RLCGeneratorTests.cs @@ -136,7 +136,7 @@ public void GenerateCapacitorWithIC() true )).Do(x => { - ((Entity)x[0]).SetParameter(((string)x[1]).ToLower(), evaluator.EvaluateValueExpression((string)x[2], new SpiceSharpParser.Common.Evaluation.ExpressionContext())); + ((Entity)x[0]).SetParameter(((string)x[1]).ToLower(), evaluator.Evaluate((string)x[2], new SpiceSharpParser.Common.Evaluation.ExpressionContext(), null, null)); }); var parameters = new ParameterCollection @@ -171,7 +171,7 @@ public void GenerateSemicondutorCapacitor() true )).Do(x => { - ((Entity)x[0]).SetParameter(((string)x[1]).ToLower(), evaluator.EvaluateValueExpression((string)x[2], new SpiceSharpParser.Common.Evaluation.ExpressionContext())); + ((Entity)x[0]).SetParameter(((string)x[1]).ToLower(), evaluator.Evaluate((string)x[2], new SpiceSharpParser.Common.Evaluation.ExpressionContext(), null, null)); }); context.ModelsRegistry.FindModel(Arg.Any()).Returns(new CapacitorModel("CModel")); diff --git a/src/SpiceSharpParser/Common/Evaluation/EvaluatedArgs.cs b/src/SpiceSharpParser/Common/Evaluation/EvaluatedArgs.cs deleted file mode 100644 index 58a9b790..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/EvaluatedArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace SpiceSharpParser.Common.Evaluation -{ - public class EvaluatedArgs : EventArgs - { - public double NewValue { get; set; } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Evaluator.cs b/src/SpiceSharpParser/Common/Evaluation/Evaluator.cs index 0434dc39..dcc2e7c0 100644 --- a/src/SpiceSharpParser/Common/Evaluation/Evaluator.cs +++ b/src/SpiceSharpParser/Common/Evaluation/Evaluator.cs @@ -1,5 +1,6 @@ using System; using SpiceSharp.Simulations; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.Parsers.Expression; @@ -38,7 +39,7 @@ public Evaluator(string name) /// /// A double value. /// - public double EvaluateValueExpression(string expression, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) + public double Evaluate(string expression, ExpressionContext context, Simulation simulation, IReadingContext readingContext) { if (expression == null) { @@ -49,13 +50,27 @@ public double EvaluateValueExpression(string expression, ExpressionContext conte { throw new ArgumentNullException(nameof(context)); } + return ExpressionParserHelpers.GetExpressionValue(expression, context, this, simulation, readingContext, false); + } - if (context.Parameters.TryGetValue(expression, out var parameter)) + public double Evaluate(Expression expression, ExpressionContext context, Simulation simulation, IReadingContext readingContext) + { + if (expression == null) { - return parameter.Evaluate(this, context, simulation, readingContext); + throw new ArgumentNullException(nameof(expression)); } - return ExpressionParserHelpers.GetExpressionValue(expression, context, this, simulation, readingContext, false); + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (expression is ConstantExpression ce) + { + return ce.Value; + } + + return Evaluate(expression.ValueExpression, context, simulation, readingContext); } } } diff --git a/src/SpiceSharpParser/Common/Evaluation/Expression.cs b/src/SpiceSharpParser/Common/Evaluation/Expression.cs index 27f449ed..25ec917a 100644 --- a/src/SpiceSharpParser/Common/Evaluation/Expression.cs +++ b/src/SpiceSharpParser/Common/Evaluation/Expression.cs @@ -1,88 +1,32 @@ using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; namespace SpiceSharpParser.Common.Evaluation { /// /// An evaluator expression. /// - public class Expression + public abstract class Expression { /// /// Initializes a new instance of the class. /// /// Expression. - public Expression(string expression) + protected Expression(string expression) { ValueExpression = expression ?? throw new ArgumentNullException(nameof(expression)); } - /// - /// Thrown when expression is evaluated. - /// - public event EventHandler Evaluated; - /// /// Gets the expression string. /// public string ValueExpression { get; } - /// - /// Gets or sets the current evaluation value. - /// - public double CurrentValue { get; protected set; } = double.NaN; - - /// - /// Evaluates the expression. - /// - /// Evaluator. - /// Context. - /// - /// - /// - /// The value of the expression. - /// - public virtual double Evaluate(IEvaluator evaluator, ExpressionContext context, Simulation simulation, IReadingContext readingContext) - { - if (evaluator == null) - { - throw new ArgumentNullException(nameof(evaluator)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - var newValue = evaluator.EvaluateValueExpression(ValueExpression, context, simulation, readingContext); - CurrentValue = newValue; - OnEvaluated(newValue); - return newValue; - } - - /// - /// Invalidates the expression. - /// - public virtual void Invalidate() - { - CurrentValue = double.NaN; - } - /// /// Clones the expression. /// /// /// A cloned expression. /// - public virtual Expression Clone() - { - return new Expression(ValueExpression); - } - - protected void OnEvaluated(double newValue) - { - Evaluated?.Invoke(this, new EvaluatedArgs() { NewValue = newValue }); - } + public abstract Expression Clone(); } } diff --git a/src/SpiceSharpParser/Common/Evaluation/ExpressionContext.cs b/src/SpiceSharpParser/Common/Evaluation/ExpressionContext.cs index 574ac657..9a0c2e6a 100644 --- a/src/SpiceSharpParser/Common/Evaluation/ExpressionContext.cs +++ b/src/SpiceSharpParser/Common/Evaluation/ExpressionContext.cs @@ -120,8 +120,6 @@ public void SetParameter(string parameterName, double value) Parameters[parameterName] = parameter; ExpressionRegistry.AddOrUpdate(parameterName, parameter); - ExpressionRegistry.InvalidateDependentParameters(parameterName); - ExpressionRegistry.InvalidateExpressions(parameterName); foreach (var child in Children) { @@ -152,34 +150,7 @@ public void SetParameter(string parameterName, string expression, ICollection - /// Sets the cached parameter. - /// - /// A name of parameter. - /// An expression of parameter. - /// Parameters in expression. - public void SetCachedParameter(string parameterName, string expression, ICollection expressionParameters) - { - if (parameterName == null) - { - throw new ArgumentNullException(nameof(parameterName)); - } - - if (expression == null) - { - throw new ArgumentNullException(nameof(expression)); - } - - if (expressionParameters == null) - { - throw new ArgumentNullException(nameof(expressionParameters)); - } - - var parameter = new CachedExpression(expression); + var parameter = new DynamicExpression(expression); SetParameter(parameterName, expression, expressionParameters, parameter); } @@ -227,14 +198,14 @@ public void SetNamedExpression(string expressionName, string expression, ICollec /// /// Expression. /// - public string GetExpression(string expressionName) + public Expression GetExpression(string expressionName) { if (expressionName == null) { throw new ArgumentNullException(nameof(expressionName)); } - return ExpressionRegistry.GetExpression(expressionName)?.ValueExpression; + return ExpressionRegistry.GetExpression(expressionName); } /// @@ -360,15 +331,9 @@ public void AddFunction(string name, IFunction function) public void CreateCommonFunctions() { - AddFunction("acos", MathFunctions.CreateACos()); - AddFunction("asin", MathFunctions.CreateASin()); - AddFunction("atan", MathFunctions.CreateATan()); AddFunction("atan2", MathFunctions.CreateATan2()); - AddFunction("cos", MathFunctions.CreateCos()); AddFunction("cosh", MathFunctions.CreateCosh()); - AddFunction("sin", MathFunctions.CreateSin()); AddFunction("sinh", MathFunctions.CreateSinh()); - AddFunction("tan", MathFunctions.CreateTan()); AddFunction("tanh", MathFunctions.CreateTanh()); } @@ -378,8 +343,6 @@ protected void SetParameter(string parameterName, string expression, ICollection ExpressionRegistry.AddOrUpdate(parameterName, parameter); ExpressionRegistry.AddOrUpdateParameterDependencies(parameterName, expressionParameters); - ExpressionRegistry.InvalidateDependentParameters(parameterName); - ExpressionRegistry.InvalidateExpressions(parameterName); foreach (var child in Children) { diff --git a/src/SpiceSharpParser/Common/Evaluation/ExpressionRegistry.cs b/src/SpiceSharpParser/Common/Evaluation/ExpressionRegistry.cs index dbafee30..e22820e4 100644 --- a/src/SpiceSharpParser/Common/Evaluation/ExpressionRegistry.cs +++ b/src/SpiceSharpParser/Common/Evaluation/ExpressionRegistry.cs @@ -211,56 +211,6 @@ public void AddOrUpdateParameterDependencies(string parameterName, ICollection - /// Refreshes the expressions in the registry that depends on the given parameter. - /// - /// Parameter name. - public void InvalidateDependentParameters(string parameterName) - { - if (parameterName == null) - { - throw new ArgumentNullException(nameof(parameterName)); - } - - if (ParametersDependencies.ContainsKey(parameterName)) - { - foreach (var parameter in ParametersDependencies[parameterName]) - { - Parameters[parameter].Invalidate(); - - InvalidateDependentParameters(parameter); - } - } - } - - /// - /// Refreshes the expressions in the registry that depends on the given parameter. - /// - /// Parameter name. - public void InvalidateExpressions(string parameterName) - { - if (parameterName == null) - { - throw new ArgumentNullException(nameof(parameterName)); - } - - if (ParametersDependencies.ContainsKey(parameterName)) - { - foreach (var parameter in ParametersDependencies[parameterName]) - { - InvalidateExpressions(parameter); - } - } - - if (ParametersExpressionsDependencies.ContainsKey(parameterName)) - { - foreach (var expression in ParametersExpressionsDependencies[parameterName]) - { - expression.Invalidate(); - } - } - } - /// /// Clones the registry. /// @@ -326,29 +276,5 @@ public ExpressionRegistry Clone() return result; } - - /// - /// Invalidates the registry. - /// - public void Invalidate() - { - foreach (var exprDep in ParametersExpressionsDependencies) - { - foreach (var expr in exprDep.Value) - { - expr.Invalidate(); - } - } - - foreach (var expression in NamedExpressions.Values) - { - expression.Invalidate(); - } - - foreach (var expression in UnnamedExpressions) - { - expression.Invalidate(); - } - } } } diff --git a/src/SpiceSharpParser/Common/Evaluation/Expressions/CachedExpression.cs b/src/SpiceSharpParser/Common/Evaluation/Expressions/CachedExpression.cs deleted file mode 100644 index 6914e41c..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Expressions/CachedExpression.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Expressions -{ - public class CachedExpression : Expression - { - /// - /// Initializes a new instance of the class. - /// - /// Expression string. - public CachedExpression(string expression) - : base(expression) - { - } - - /// - /// Gets a value indicating whether value of cached expression has been computed. - /// - protected bool IsEvaluated { get; private set; } - - /// - /// Evaluates the expression. - /// - /// Evaluator. - /// Context. - /// Simulation. - /// Reading context. - /// - /// The value of the expression. - /// - public override double Evaluate(IEvaluator evaluator, ExpressionContext context, Simulation sim, IReadingContext readingContext) - { - if (evaluator == null) - { - throw new ArgumentNullException(nameof(evaluator)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - if (!IsEvaluated) - { - CurrentValue = evaluator.EvaluateValueExpression(ValueExpression,context, sim, readingContext); - IsEvaluated = true; - } - - return CurrentValue; - } - - /// - /// Invalidate the expression. - /// - public override void Invalidate() - { - IsEvaluated = false; - } - - /// - /// Clones the cached expression. - /// - /// - /// A cloned cached expression. - /// - public override Expression Clone() - { - return new CachedExpression(ValueExpression) { CurrentValue = CurrentValue, IsEvaluated = true }; - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Expressions/ConstantExpression.cs b/src/SpiceSharpParser/Common/Evaluation/Expressions/ConstantExpression.cs index 955b2555..2783451f 100644 --- a/src/SpiceSharpParser/Common/Evaluation/Expressions/ConstantExpression.cs +++ b/src/SpiceSharpParser/Common/Evaluation/Expressions/ConstantExpression.cs @@ -1,8 +1,4 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Expressions +namespace SpiceSharpParser.Common.Evaluation.Expressions { public class ConstantExpression : Expression { @@ -10,12 +6,13 @@ public class ConstantExpression : Expression /// Initializes a new instance of the class. /// /// Value. - public ConstantExpression(double value) - : base(string.Empty) + public ConstantExpression(double value) : base(string.Empty) { - CurrentValue = value; + Value = value; } + public double Value { get; } + /// /// Clones the named expression. /// @@ -24,26 +21,7 @@ public ConstantExpression(double value) /// public override Expression Clone() { - return new ConstantExpression(CurrentValue); - } - - public override void Invalidate() - { - } - - public override double Evaluate(IEvaluator evaluator, ExpressionContext context, Simulation sim, IReadingContext readingContext) - { - if (evaluator == null) - { - throw new ArgumentNullException(nameof(evaluator)); - } - - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - - return CurrentValue; + return new ConstantExpression(Value); } } } diff --git a/src/SpiceSharpParser/Common/Evaluation/Expressions/DynamicExpression.cs b/src/SpiceSharpParser/Common/Evaluation/Expressions/DynamicExpression.cs new file mode 100644 index 00000000..824cedca --- /dev/null +++ b/src/SpiceSharpParser/Common/Evaluation/Expressions/DynamicExpression.cs @@ -0,0 +1,14 @@ +namespace SpiceSharpParser.Common.Evaluation.Expressions +{ + public class DynamicExpression : Expression + { + public DynamicExpression(string expression) : base(expression) + { + } + + public override Expression Clone() + { + return new DynamicExpression(ValueExpression); + } + } +} diff --git a/src/SpiceSharpParser/Common/Evaluation/Function.cs b/src/SpiceSharpParser/Common/Evaluation/Function.cs index caa9efb3..996404f9 100644 --- a/src/SpiceSharpParser/Common/Evaluation/Function.cs +++ b/src/SpiceSharpParser/Common/Evaluation/Function.cs @@ -15,11 +15,6 @@ public abstract class Function : IFunction public int ArgumentsCount { get; set; } - /// - /// Gets or sets a value indicating whether function is infix. - /// - public bool Infix { get; set; } - /// /// Computes the value of the function for given arguments. /// diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/ExpressionFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/ExpressionFunction.cs index 59251e12..4f7d28a1 100644 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/ExpressionFunction.cs +++ b/src/SpiceSharpParser/Common/Evaluation/Functions/ExpressionFunction.cs @@ -76,6 +76,11 @@ public Derivatives> Derivative(string image, double[] args, IEvalua throw new ArgumentNullException(nameof(context)); } + if (readingContext == null) + { + throw new ArgumentNullException(nameof(readingContext)); + } + var childContext = context.CreateChildContext(string.Empty, false); for (var i = 0; i < Arguments.Count; i++) { @@ -83,7 +88,7 @@ public Derivatives> Derivative(string image, double[] args, IEvalua childContext.Arguments.Add(Arguments[i], new ConstantExpression(args[i])); } - var parser = ExpressionParserHelpers.GetDeriveParser(childContext, readingContext, evaluator, simulation); + var parser = ExpressionParserHelpers.GetDeriveParser(childContext, readingContext, evaluator, simulation, readingContext.CaseSensitivity); var parseResult = parser.Parse(Expression); return parseResult; } diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ACosFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ACosFunction.cs deleted file mode 100644 index 48cb5f12..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ACosFunction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Functions.Math -{ - public class ACosFunction : Function - { - public ACosFunction() - { - Name = "acos"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("acos() function expects one argument"); - } - - double d = args[0]; - return System.Math.Acos(d); - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ASinFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ASinFunction.cs deleted file mode 100644 index 7bfac2b7..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ASinFunction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Functions.Math -{ - public class ASinFunction : Function - { - public ASinFunction() - { - Name = "asin"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("asin() function expects one argument"); - } - - double d = args[0]; - return System.Math.Asin(d); - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ATanFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ATanFunction.cs deleted file mode 100644 index 309d5776..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/ATanFunction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Functions.Math -{ - public class ATanFunction : Function - { - public ATanFunction() - { - Name = "atan"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("atan() function expects one argument"); - } - - double d = args[0]; - return System.Math.Atan(d); - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/CosFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/Math/CosFunction.cs deleted file mode 100644 index 12f56624..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/CosFunction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Functions.Math -{ - public class CosFunction : Function - { - public CosFunction() - { - Name = "cos"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("cos() function expects one argument"); - } - - double d = args[0]; - return System.Math.Cos(d); - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/SinFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/Math/SinFunction.cs deleted file mode 100644 index 67a4e09b..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/SinFunction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Functions.Math -{ - public class SinFunction : Function - { - public SinFunction() - { - Name = "sin"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("sin() function expects one argument"); - } - - double d = args[0]; - return System.Math.Sin(d); - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/TanFunction.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/Math/TanFunction.cs deleted file mode 100644 index a14d7165..00000000 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/Math/TanFunction.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.Common.Evaluation.Functions.Math -{ - public class TanFunction : Function - { - public TanFunction() - { - Name = "tan"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("tan() function expects one argument"); - } - - double d = args[0]; - return System.Math.Tan(d); - } - } -} diff --git a/src/SpiceSharpParser/Common/Evaluation/Functions/MathFunctions.cs b/src/SpiceSharpParser/Common/Evaluation/Functions/MathFunctions.cs index c5c704eb..5352f2f6 100644 --- a/src/SpiceSharpParser/Common/Evaluation/Functions/MathFunctions.cs +++ b/src/SpiceSharpParser/Common/Evaluation/Functions/MathFunctions.cs @@ -4,39 +4,6 @@ namespace SpiceSharpParser.Common.Evaluation.Functions { public class MathFunctions { - /// - /// Get a cos() function. - /// - /// - /// A new instance of cos() function. - /// - public static IFunction CreateCos() - { - return new CosFunction(); - } - - /// - /// Get a sin() function. - /// - /// - /// A new instance of sin() function. - /// - public static IFunction CreateSin() - { - return new SinFunction(); - } - - /// - /// Get a tan() function. - /// - /// - /// A new instance of tan() function. - /// - public static IFunction CreateTan() - { - return new TanFunction(); - } - /// /// Get a cosh() function. /// @@ -70,39 +37,6 @@ public static IFunction CreateTanh() return new TanhFunction(); } - /// - /// Get a acos() function. - /// - /// - /// A new instance of acos() function. - /// - public static IFunction CreateACos() - { - return new ACosFunction(); - } - - /// - /// Get a asin() function. - /// - /// - /// A new instance of asin() function. - /// - public static IFunction CreateASin() - { - return new ASinFunction(); - } - - /// - /// Get a atan() function. - /// - /// - /// A new instance of atan() function. - /// - public static IFunction CreateATan() - { - return new ATanFunction(); - } - /// /// Get a atan() function. /// diff --git a/src/SpiceSharpParser/Common/Evaluation/IEvaluator.cs b/src/SpiceSharpParser/Common/Evaluation/IEvaluator.cs index 78ecb02e..96171ebe 100644 --- a/src/SpiceSharpParser/Common/Evaluation/IEvaluator.cs +++ b/src/SpiceSharpParser/Common/Evaluation/IEvaluator.cs @@ -8,6 +8,6 @@ namespace SpiceSharpParser.Common.Evaluation /// public interface IEvaluator { - double EvaluateValueExpression(string expression, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null); + double Evaluate(Expression expression, ExpressionContext context, Simulation simulation, IReadingContext readingContext); } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs index 1319989e..f1fa780f 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/ReadingContext.cs @@ -5,6 +5,7 @@ using SpiceSharp.Circuits; using SpiceSharpParser.Common; using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Models; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Names; using SpiceSharpParser.ModelReaders.Netlist.Spice.Exceptions; @@ -210,7 +211,7 @@ public double EvaluateDouble(string expression) } try { - return ReadingEvaluator.EvaluateValueExpression(expression, ReadingExpressionContext); + return ReadingEvaluator.Evaluate(new DynamicExpression(expression), ReadingExpressionContext, null, this); } catch (Exception ex) { @@ -296,7 +297,8 @@ public void SetParameter(string parameterName, string expression) throw new ArgumentNullException(nameof(expression)); } - var parameters = ExpressionParserHelpers.GetExpressionParameters(expression, ReadingExpressionContext, this, false); + var parameters = ExpressionParserHelpers.GetExpressionParameters(expression, ReadingExpressionContext, this, CaseSensitivity, false); + ReadingExpressionContext.SetParameter( parameterName, expression, @@ -335,7 +337,7 @@ public void SetNamedExpression(string expressionName, string expression) throw new ArgumentNullException(nameof(expression)); } - var parameters = ExpressionParserHelpers.GetExpressionParameters(expression, ReadingExpressionContext, this, false); + var parameters = ExpressionParserHelpers.GetExpressionParameters(expression, ReadingExpressionContext, this, CaseSensitivity, false); ReadingExpressionContext.SetNamedExpression(expressionName, expression, parameters); } @@ -358,7 +360,7 @@ public void SetParameter(Entity entity, string parameterName, string expression, IEqualityComparer comparer = StringComparerProvider.Get(CaseSensitivity.IsEntityParameterNameCaseSensitive); - double value = ReadingEvaluator.EvaluateValueExpression(expression, ReadingExpressionContext, null, this); + double value = ReadingEvaluator.Evaluate(new DynamicExpression(expression), ReadingExpressionContext, null, this); try { @@ -370,8 +372,8 @@ public void SetParameter(Entity entity, string parameterName, string expression, } bool isDynamic = ExpressionParserHelpers.HaveSpiceProperties(expression, ReadingExpressionContext, this, false) - || ExpressionParserHelpers.HaveFunctions(expression, ReadingExpressionContext, this, false) - || ExpressionParserHelpers.GetExpressionParameters(expression, ReadingExpressionContext, this, false).Any(); + || ExpressionParserHelpers.HaveFunctions(expression, ReadingExpressionContext, this) + || ExpressionParserHelpers.GetExpressionParameters(expression, ReadingExpressionContext, this, CaseSensitivity, false).Any(); if (isDynamic) { diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/SimulationPreparations.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/SimulationPreparations.cs index 6cf22795..59db532b 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/SimulationPreparations.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/SimulationPreparations.cs @@ -3,6 +3,7 @@ using SpiceSharp.Behaviors; using SpiceSharp.Circuits; using SpiceSharp.Simulations; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Updates; namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Context @@ -57,7 +58,7 @@ public void SetNodeSetVoltage(string nodeId, string expression, IReadingContext { var simEval = evaluators.GetEvaluator(simulation); var context = contexts.GetContext(simulation); - var value = simEval.EvaluateValueExpression(expression, context, simulation, readingContext); + var value = simEval.Evaluate(new DynamicExpression(expression), context, simulation, readingContext); simulation.Configurations.Get().Nodesets[nodeId] = value; }); @@ -79,7 +80,7 @@ public void SetICVoltage(string nodeId, string expression, IReadingContext readi { var simEval = evaluators.GetEvaluator(simulation); var context = contexts.GetContext(simulation); - var value = simEval.EvaluateValueExpression(expression, context, simulation, readingContext); + var value = simEval.Evaluate(new DynamicExpression(expression), context, simulation, readingContext); if (simulation is TimeSimulation ts) { diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityParameterExpressionValueUpdate.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityParameterExpressionValueUpdate.cs index 3af6cfd3..c1f6a439 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityParameterExpressionValueUpdate.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityParameterExpressionValueUpdate.cs @@ -7,7 +7,7 @@ namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Updates public class EntityParameterExpressionValueUpdate : EntityParameterUpdate { private readonly IReadingContext _readingContext; - public string ValueExpression { get; set; } + public Expression Expression { get; set; } public EntityParameterExpressionValueUpdate(IReadingContext readingContext) { @@ -27,7 +27,7 @@ public override double GetValue(IEvaluator evaluator, ExpressionContext context, throw new ArgumentNullException(nameof(context)); } - return evaluator.EvaluateValueExpression(ValueExpression, context, simulation, _readingContext); + return evaluator.Evaluate(Expression, context, simulation, _readingContext); } } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityUpdates.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityUpdates.cs index 4ac7bdc8..00f3690b 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityUpdates.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityUpdates.cs @@ -5,6 +5,7 @@ using SpiceSharp.Circuits; using SpiceSharp.Simulations; using SpiceSharpParser.Common; +using SpiceSharpParser.Common.Evaluation.Expressions; namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Updates { @@ -170,13 +171,17 @@ public void Add(Entity entity, string parameterName, string expression, bool bef new EntityParameterExpressionValueUpdate(readingContext) { ParameterName = parameterName, - ValueExpression = expression, + Expression = new DynamicExpression(expression), }); } if (beforeTemperature) { - CommonUpdates[entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate(readingContext) { ValueExpression = expression, ParameterName = parameterName }); + CommonUpdates[entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate(readingContext) + { + Expression = new DynamicExpression(expression), + ParameterName = parameterName + }); } } @@ -213,13 +218,17 @@ public void Add(Entity entity, Simulation simulation, string parameterName, stri new EntityParameterExpressionValueUpdate(readingContext) { ParameterName = parameterName, - ValueExpression = expression, + Expression = new DynamicExpression(expression), }); } if (beforeTemperature) { - SimulationSpecificUpdates[simulation][entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate(readingContext) { ValueExpression = expression, ParameterName = parameterName }); + SimulationSpecificUpdates[simulation][entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate(readingContext) + { + Expression = new DynamicExpression(expression), + ParameterName = parameterName + }); } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/AbsFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/AbsFunction.cs deleted file mode 100644 index e1dc32e5..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/AbsFunction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class AbsFunction : Function - { - public AbsFunction() - { - Name = "abs"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("abs() function expects one argument"); - } - - double x = args[0]; - return System.Math.Abs(x); - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/ExpFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/ExpFunction.cs deleted file mode 100644 index 58014296..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/ExpFunction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.Common.Evaluation; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class ExpFunction : Function - { - public ExpFunction() - { - Name = "exp"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("exp() function expects one argument"); - } - - double x = args[0]; - return System.Math.Exp(x); - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/FAbsFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/FAbsFunction.cs deleted file mode 100644 index 7e918b13..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/FAbsFunction.cs +++ /dev/null @@ -1,27 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class FAbsFunction : Function - { - public FAbsFunction() - { - Name = "fabs"; - ArgumentsCount = 1; - } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("fabs() function expects one argument"); - } - - double x = args[0]; - return System.Math.Abs(x); - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/Log10Function.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/Log10Function.cs deleted file mode 100644 index be7daf42..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/Log10Function.cs +++ /dev/null @@ -1,36 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class Log10Function : Function - { - public Log10Function(SpiceExpressionMode mode) - { - Name = "log10"; - ArgumentsCount = 1; - Mode = mode; - } - - public SpiceExpressionMode Mode { get; } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("log10() function expects one argument"); - } - - double x = args[0]; - - if (Mode == SpiceExpressionMode.HSpice) - { - return System.Math.Sign(x) * System.Math.Log10(System.Math.Abs(x)); - } - - return System.Math.Log10(x); - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/LogFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/LogFunction.cs deleted file mode 100644 index 9d16b4da..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/LogFunction.cs +++ /dev/null @@ -1,36 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class LogFunction : Function - { - public LogFunction(SpiceExpressionMode mode) - { - Name = "log"; - ArgumentsCount = 1; - Mode = mode; - } - - public SpiceExpressionMode Mode { get; } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - if (args.Length != 1) - { - throw new ArgumentException("log() function expects one argument"); - } - - double x = args[0]; - - if (Mode == SpiceExpressionMode.HSpice) - { - return System.Math.Sign(x) * System.Math.Log(System.Math.Abs(x)); - } - - return System.Math.Log(x); - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/PowFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/PowFunction.cs deleted file mode 100644 index c00f123a..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/PowFunction.cs +++ /dev/null @@ -1,51 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System.Numerics; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class PowFunction : Function - { - public PowFunction(SpiceExpressionMode mode) - { - Name = "pow"; - ArgumentsCount = 2; - Mode = mode; - } - - public SpiceExpressionMode Mode { get; } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - double x = args[0]; - double y = args[1]; - - switch (Mode) - { - case SpiceExpressionMode.LtSpice: - if (x < 0) - { - var realResult = Complex.Pow(new Complex(x, 0), new Complex(y, 0)).Real; - - // TODO: remove a hack below, write a good implementation of Complex numbers for C# ... - if (System.Math.Abs(realResult) < 1e-15) - { - return 0; - } - } - - return System.Math.Pow(x, y); - - case SpiceExpressionMode.SmartSpice: - return System.Math.Pow(System.Math.Abs(x), (int)y); - - case SpiceExpressionMode.HSpice: - return System.Math.Pow(x, (int)y); - - default: - return System.Math.Pow(x, y); - } - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/PowInfixFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/PowInfixFunction.cs deleted file mode 100644 index 9ee82167..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/PowInfixFunction.cs +++ /dev/null @@ -1,64 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System; -using System.Numerics; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class PowInfixFunction : Function - { - public PowInfixFunction(SpiceExpressionMode mode) - { - Name = "**"; - ArgumentsCount = 2; - Infix = true; - Mode = mode; - } - - public SpiceExpressionMode Mode { get; } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - double x = args[0]; - double y = args[1]; - - switch (Mode) - { - case SpiceExpressionMode.LtSpice: - if (x < 0) - { - var realResult = Complex.Pow(new Complex(x, 0), new Complex(y, 0)).Real; - - // TODO: remove a hack below, write a good implementation of Complex numbers for C# ... - if (System.Math.Abs(realResult) < 1e-15) - { - return 0; - } - } - - return System.Math.Pow(x, y); - - case SpiceExpressionMode.SmartSpice: - throw new Exception("** is unknown function"); - - case SpiceExpressionMode.HSpice: - if (x < 0) - { - return System.Math.Pow(x, (int)y); - } - else if (x == 0) - { - return 0; - } - else - { - return System.Math.Pow(x, y); - } - - default: - return System.Math.Pow(x, y); - } - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/SqrtFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/SqrtFunction.cs deleted file mode 100644 index b76f8186..00000000 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/SqrtFunction.cs +++ /dev/null @@ -1,57 +0,0 @@ -using SpiceSharpParser.Common.Evaluation; -using System.Numerics; -using SpiceSharp.Simulations; -using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; - -namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math -{ - public class SqrtFunction : Function - { - public SqrtFunction(SpiceExpressionMode mode) - { - Name = "sqrt"; - ArgumentsCount = 1; - Mode = mode; - } - - public SpiceExpressionMode Mode { get; } - - public override double Logic(string image, double[] args, IEvaluator evaluator, ExpressionContext context, Simulation simulation = null, IReadingContext readingContext = null) - { - double x = args[0]; - - switch (Mode) - { - case SpiceExpressionMode.LtSpice: - if (x < 0) - { - var realResult = Complex.Pow(new Complex(x, 0), new Complex(0.5, 0)).Real; - - // TODO: remove a hack below, write a good implementation of Complex numbers for C# ... - if (System.Math.Abs(realResult) < 1e-15) - { - return 0; - } - } - - return System.Math.Sqrt(x); - - case SpiceExpressionMode.SmartSpice: - return System.Math.Sqrt(System.Math.Abs(x)); - - case SpiceExpressionMode.HSpice: - if (x < 0) - { - return -System.Math.Sqrt(System.Math.Abs(x)); - } - else - { - return System.Math.Sqrt(x); - } - - default: - return System.Math.Sqrt(x); - } - } - } -} diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/TableFunction.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/TableFunction.cs index cafbd91c..e2ce4a2c 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/TableFunction.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/Math/TableFunction.cs @@ -1,12 +1,14 @@ using SpiceSharpParser.Common.Evaluation; using System; using System.Collections.Generic; +using System.Linq; using SpiceSharp.Simulations; +using SpiceSharpBehavioral.Parsers; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Evaluation.Functions.Math { - public class TableFunction : Function + public class TableFunction : Function, IDerivativeFunction { public TableFunction() { @@ -18,13 +20,13 @@ public override double Logic(string image, double[] args, IEvaluator evaluator, { var parameterValue = args[0]; - var points = new List>(); + var points = new List(); for (var i = 1; i < args.Length - 1; i += 2) { var pointX = args[i]; var pointY = args[i + 1]; - points.Add(new Tuple(pointX, pointY)); + points.Add(new Point() {X = pointX, Y = pointY}); if (pointX == parameterValue) { @@ -32,7 +34,7 @@ public override double Logic(string image, double[] args, IEvaluator evaluator, } } - points.Sort((x1, x2) => x1.Item1.CompareTo(x2.Item1)); + points.Sort((p1, p2) => p1.X.CompareTo(p2.X)); if (points.Count == 1) { throw new Exception("There is only one point for table interpolation."); @@ -43,35 +45,35 @@ public override double Logic(string image, double[] args, IEvaluator evaluator, int index = 0; - while (index < points.Count && points[index].Item1 < parameterValue) + while (index < points.Count && points[index].X < parameterValue) { index++; } if (index == points.Count) { - return points[points.Count - 1].Item2; + return points[points.Count - 1].Y; } - if (index == 0 && points[0].Item1 > parameterValue) + if (index == 0 && points[0].X > parameterValue) { - return points[0].Item2; + return points[0].Y; } return (linesDefinition[index].A * parameterValue) + linesDefinition[index].B; } - private static LineDefinition[] CreateLineParameters(List> points) + private static LineDefinition[] CreateLineParameters(List points) { List result = new List(); for (var i = 0; i < points.Count - 1; i++) { - double x1 = points[i].Item1; - double x2 = points[i + 1].Item1; - double y1 = points[i].Item2; - double y2 = points[i + 1].Item2; + double x1 = points[i].X; + double x2 = points[i + 1].X; + double y1 = points[i].Y; + double y2 = points[i + 1].Y; double a = (y2 - y1) / (x2 - x1); @@ -93,5 +95,72 @@ public class LineDefinition public double B { get; set; } } + + public class Point + { + public double X { get; set; } + + public double Y { get; set; } + } + + public Derivatives> Derivative(string image, double[] args, IEvaluator evaluator, ExpressionContext context, + Simulation simulation = null, IReadingContext readingContext = null) + { + var parameterValue = args[0]; + var points = new List(); + Derivatives> derivatives; + + for (var i = 1; i < args.Length - 1; i += 2) + { + var pointX = args[i]; + var pointY = args[i + 1]; + points.Add(new Point() { X = pointX, Y = pointY }); + + if (pointX == parameterValue) + { + derivatives = new DoubleDerivatives(1); + derivatives[0] = () => pointY; + return derivatives; + } + } + + points.Sort((p1, p2) => p1.X.CompareTo(p2.X)); + if (points.Count == 1) + { + throw new Exception("There is only one point for table interpolation."); + } + + // Get point + 1 line parameters for each segment of line + LineDefinition[] linesDefinition = CreateLineParameters(points); + + int index = 0; + + while (index < points.Count && points[index].X < parameterValue) + { + index++; + } + + if (index == points.Count) + { + derivatives = new DoubleDerivatives(2); + derivatives[0] = () => points[points.Count - 1].Y; + derivatives[1] = () => linesDefinition.Last().A; + + return derivatives; + } + + if (index == 0 && points[0].X > parameterValue) + { + derivatives = new DoubleDerivatives(2); + derivatives[0] = () => points[0].Y; + derivatives[1] = () => linesDefinition.First().A; + } + + derivatives = new DoubleDerivatives(2); + derivatives[0] = () => linesDefinition[index].A * parameterValue + linesDefinition[index].B; + derivatives[1] = () => linesDefinition[index].A; + + return derivatives; + } } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/MathFunctions.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/MathFunctions.cs index 7057aa9b..7fce9581 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/MathFunctions.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/Functions/MathFunctions.cs @@ -27,18 +27,6 @@ public static IFunction CreatePoly() return new PolyFunction(); } - /// - /// Get a pow() function. - /// - /// Evaluator mode. - /// - /// A new instance of pow function. - /// - public static IFunction CreatePow(SpiceExpressionMode mode) - { - return new PowFunction(mode); - } - /// /// Get a pwr() function. /// @@ -62,30 +50,6 @@ public static IFunction CreatePwrs() return new PwrsFunction(); } - /// - /// Get a sqrt function. - /// - /// Evaluator mode. - /// - /// A new instance of pow function. - /// - public static IFunction CreateSqrt(SpiceExpressionMode mode) - { - return new SqrtFunction(mode); - } - - /// - /// Get a ** function. - /// - /// Evaluator mode. - /// - /// A new instance of ** function. - /// - public static IFunction CreatePowInfix(SpiceExpressionMode mode) - { - return new PowInfixFunction(mode); - } - /// /// Get a min() function. /// @@ -141,28 +105,6 @@ public static IFunction CreateLn() return new LnFunction(); } - /// - /// Get a log() function. - /// - /// - /// A new instance of log function. - /// - public static IFunction CreateLog(SpiceExpressionMode mode) - { - return new LogFunction(mode); - } - - /// - /// Get a log10() function. - /// - /// - /// A new instance of log10 function. - /// - public static IFunction CreateLog10(SpiceExpressionMode mode) - { - return new Log10Function(mode); - } - /// /// Get a cbrt() function. /// @@ -196,28 +138,6 @@ public static IFunction CreateCeil() return new CeilFunction(); } - /// - /// Get a abs() function. - /// - /// - /// A new instance of abs function. - /// - public static IFunction CreateAbs() - { - return new AbsFunction(); - } - - /// - /// Get a fabs() function. - /// - /// - /// A new instance of fabs function. - /// - public static IFunction CreateFAbs() - { - return new FAbsFunction(); - } - /// /// Get a floor() function. /// @@ -262,17 +182,6 @@ public static IFunction CreateInv() return new InvFunction(); } - /// - /// Get a exp() function. - /// - /// - /// A new instance of exp function. - /// - public static IFunction CreateExp() - { - return new ExpFunction(); - } - /// /// Get a db() function. /// diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/SpiceExpressionContext.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/SpiceExpressionContext.cs index 4a6eb421..bb762f55 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/SpiceExpressionContext.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Evaluation/SpiceExpressionContext.cs @@ -38,8 +38,6 @@ private void CreateSpiceFunctions() var functions = new List { MathFunctions.CreatePos(), - MathFunctions.CreatePowInfix(Mode), - MathFunctions.CreateAbs(), RandomFunctions.CreateAGauss(), RandomFunctions.CreateAUnif(), MathFunctions.CreateBuf(), @@ -47,8 +45,6 @@ private void CreateSpiceFunctions() MathFunctions.CreateCeil(), MathFunctions.CreateDb(Mode), ControlFunctions.CreateDef(), - MathFunctions.CreateExp(), - MathFunctions.CreateFAbs(), RandomFunctions.CreateFlat(), MathFunctions.CreateFloor(), RandomFunctions.CreateGauss(), @@ -60,18 +56,14 @@ private void CreateSpiceFunctions() MathFunctions.CreateLn(), MathFunctions.CreateLimit(), RandomFunctions.CreateLimit(), - MathFunctions.CreateLog(Mode), - MathFunctions.CreateLog10(Mode), MathFunctions.CreateMax(), RandomFunctions.CreateMc(), MathFunctions.CreateMin(), MathFunctions.CreateNint(), MathFunctions.CreateRound(), - MathFunctions.CreatePow(Mode), MathFunctions.CreatePwr(Mode), MathFunctions.CreatePwrs(), RandomFunctions.CreateRandom(), - MathFunctions.CreateSqrt(Mode), MathFunctions.CreateSgn(), MathFunctions.CreateTable(), MathFunctions.CreateU(), diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Processors/IfPreprocessor.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Processors/IfPreprocessor.cs index 26690da6..9eec21e8 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Processors/IfPreprocessor.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Processors/IfPreprocessor.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.Controls; using SpiceSharpParser.Models.Netlist.Spice.Objects; @@ -121,7 +122,7 @@ private IEnumerable ComputeIfResult(Statements result, int ifIndex, i elseIfControl = result[elseIfControlIndex] as Control; } - if (Evaluator.EvaluateValueExpression(ifCondition.Image, ExpressionContext) >= 1.0) + if (Evaluator.Evaluate(new DynamicExpression(ifCondition.Image), ExpressionContext, null, null) >= 1.0) { if (elseIfControl != null) { diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/Exporter.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/Exporter.cs index 87ce10c2..77f34bb8 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/Exporter.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/Exporter.cs @@ -20,11 +20,10 @@ public abstract class Exporter /// Node name generator. /// Component name generator. /// Model name generator. - /// Result. /// Case settings. /// /// A new export. /// - public abstract Export CreateExport(string name, string type, ParameterCollection parameters, Simulation simulation, INodeNameGenerator nodeNameGenerator, IObjectNameGenerator componentNameGenerator, IObjectNameGenerator modelNameGenerator, IResultService result, SpiceNetlistCaseSensitivitySettings caseSettings); + public abstract Export CreateExport(string name, string type, ParameterCollection parameters, Simulation simulation, INodeNameGenerator nodeNameGenerator, IObjectNameGenerator componentNameGenerator, IObjectNameGenerator modelNameGenerator, IResultService resultService, SpiceNetlistCaseSensitivitySettings caseSettings); } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/ExpressionExport.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/ExpressionExport.cs index 40d5079e..77bfbef2 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/ExpressionExport.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Exporters/ExpressionExport.cs @@ -19,7 +19,7 @@ public class ExpressionExport : Export /// Contexts. /// Simulation. /// Reading context. - public ExpressionExport(string name, string expressionName, string expression, IEvaluator evaluator, SimulationExpressionContexts contexts, Simulation simulation, IReadingContext readingContext) + public ExpressionExport(string name, string expressionName, Expression expression, IEvaluator evaluator, SimulationExpressionContexts contexts, Simulation simulation, IReadingContext readingContext) : base(simulation) { Name = name; @@ -51,12 +51,12 @@ public ExpressionExport(string name, string expressionName, string expression, I /// /// Gets the expression. /// - public string Expression { get; } + public Expression Expression { get; } /// /// Gets the type name. /// - public override string TypeName => Expression; + public override string TypeName => Expression.ValueExpression; /// /// Gets the export unit. @@ -71,7 +71,7 @@ public ExpressionExport(string name, string expressionName, string expression, I /// public override double Extract() { - return Evaluator.EvaluateValueExpression(Expression, ExpressionContexts.GetContext(Simulation), Simulation, ReadingContext); + return Evaluator.Evaluate(Expression, ExpressionContexts.GetContext(Simulation), Simulation, ReadingContext); } } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/ParamControl.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/ParamControl.cs index 95caf35d..47603dac 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/ParamControl.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/ParamControl.cs @@ -12,7 +12,7 @@ public class ParamControl : ParamBaseControl { protected override void SetParameter(string parameterName, string parameterExpression, ExpressionContext expressionContext, SpiceNetlistCaseSensitivitySettings caseSettings, IEvaluator evaluator, IReadingContext readingContext) { - var parameters = ExpressionParserHelpers.GetExpressionParameters(parameterExpression, expressionContext, readingContext, @throw: false); + var parameters = ExpressionParserHelpers.GetExpressionParameters(parameterExpression, expressionContext, readingContext, caseSettings, @throw: false); expressionContext.SetParameter(parameterName, parameterExpression, parameters); } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SParamControl.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SParamControl.cs index 575ff6a0..09ef6994 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SParamControl.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SParamControl.cs @@ -1,7 +1,7 @@ using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.Models.Netlist.Spice.Objects; -using SpiceSharpParser.Parsers.Expression; namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.Controls { @@ -12,8 +12,8 @@ public class SParamControl : ParamBaseControl { protected override void SetParameter(string parameterName, string parameterExpression, ExpressionContext expressionContext, SpiceNetlistCaseSensitivitySettings caseSettings, IEvaluator evaluator, IReadingContext readingContext) { - var parameters = ExpressionParserHelpers.GetExpressionParameters(parameterExpression, expressionContext, readingContext, false); - expressionContext.SetCachedParameter(parameterName, parameterExpression, parameters); + var value = readingContext.ReadingEvaluator.Evaluate(new DynamicExpression(parameterExpression), expressionContext, null, readingContext); + expressionContext.SetParameter(parameterName, value); } } } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SaveControl.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SaveControl.cs index fa9bf5d7..2965bcaf 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SaveControl.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/SaveControl.cs @@ -218,8 +218,8 @@ private void AddOpPointToSeries(ParameterSweep firstParameterSweep, Export expor var expressionContext = context.SimulationExpressionContexts.GetContext(export.Simulation); var firstParameterSweepParameter = expressionContext.Parameters[firstParameterSweep.Parameter.Image]; var evaluator = context.SimulationEvaluators.GetEvaluator(export.Simulation); - var value = firstParameterSweepParameter.Evaluate(evaluator, context.SimulationExpressionContexts.GetContext(export.Simulation), export.Simulation, context); - + + var value = evaluator.Evaluate(firstParameterSweepParameter, expressionContext, export.Simulation, context); series.Points.Add(new Point() { X = value, Y = export.Extract() }); }; } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Simulations/Decorators/EnableStochasticModelsSimulationDecorator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Simulations/Decorators/EnableStochasticModelsSimulationDecorator.cs index 71ec511f..9f1f5ab5 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Simulations/Decorators/EnableStochasticModelsSimulationDecorator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Simulations/Decorators/EnableStochasticModelsSimulationDecorator.cs @@ -5,6 +5,7 @@ using SpiceSharp.Simulations; using SpiceSharpParser.Common; using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Models; using SpiceSharpParser.Models.Netlist.Spice.Objects; @@ -73,7 +74,7 @@ private void SetModelLotModelParameters(BaseSimulation sim, Entity baseModel, En var expressionContext = _context.SimulationExpressionContexts.GetContext(sim); var currentValue = currentValueParameter.Value; - var percentValue = evaluator.EvaluateValueExpression(parameterPercent.Tolerance.Image, expressionContext); + var percentValue = evaluator.Evaluate(new DynamicExpression(parameterPercent.Tolerance.Image), expressionContext, null, _context); double newValue = GetValueForLotParameter(expressionContext, baseModel, parameterName, currentValue, percentValue, parameterPercent.RandomDistributionName, comparer); _context.SimulationPreparations.SetParameter(componentModel, sim, parameterName, newValue, true, false); @@ -97,7 +98,7 @@ private void SetModelDevModelParameters(BaseSimulation sim, Entity baseModel, En var currentValueParameter = sim.EntityParameters[componentModel.Name].GetParameter>(parameterName, comparer); var currentValue = currentValueParameter.Value; var expressionContext = _context.SimulationExpressionContexts.GetContext(sim); - var percentValue = evaluator.EvaluateValueExpression(parameterPercent.Tolerance.Image, expressionContext); + var percentValue = evaluator.Evaluate(new DynamicExpression(parameterPercent.Tolerance.Image), expressionContext, sim, _context); double newValue = GetValueForDevParameter(expressionContext, currentValue, percentValue, parameterPercent.RandomDistributionName); diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/ArbitraryBehavioralGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/ArbitraryBehavioralGenerator.cs index 1fa7860c..09fee046 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/ArbitraryBehavioralGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/ArbitraryBehavioralGenerator.cs @@ -1,9 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using SpiceSharp.Components; using SpiceSharp.Simulations; -using SpiceSharpBehavioral.Parsers; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.Models.Netlist.Spice.Objects; using SpiceSharpParser.Models.Netlist.Spice.Objects.Parameters; @@ -29,9 +27,10 @@ public override SpiceSharp.Components.Component Generate( { if (parameters.Any(p => p is AssignmentParameter asgParameter && asgParameter.Name.ToLower() == "v")) { - var expressionParameter = (AssignmentParameter) parameters.First(p => p is AssignmentParameter asgParameter && asgParameter.Name.ToLower() == "v"); var entity = new BehavioralVoltageSource(componentIdentifier); context.CreateNodes(entity, parameters); + + var expressionParameter = (AssignmentParameter)parameters.First(p => p is AssignmentParameter asgParameter && asgParameter.Name.ToLower() == "v"); var baseParameters = entity.ParameterSets.Get(); baseParameters.Expression = expressionParameter.Value; baseParameters.Parser = (Simulation sim) => CreateParser(context, sim); @@ -40,15 +39,16 @@ public override SpiceSharp.Components.Component Generate( if (parameters.Any(p => p is AssignmentParameter asgParameter && asgParameter.Name.ToLower() == "i")) { - var expressionParameter = (AssignmentParameter) parameters.First(p => - p is AssignmentParameter asgParameter && asgParameter.Name.ToLower() == "i"); - + var entity = new BehavioralCurrentSource(componentIdentifier); - entity.SetParameter>>("parser", (Simulation sim) => CreateParser(context, sim), null); - context.CreateNodes(entity, parameters); + + var expressionParameter = (AssignmentParameter)parameters.First(p => + p is AssignmentParameter asgParameter && asgParameter.Name.ToLower() == "i"); + var baseParameters = entity.ParameterSets.Get(); baseParameters.Expression = expressionParameter.Value; + baseParameters.Parser = (Simulation sim) => CreateParser(context, sim); return entity; } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/CurrentSourceGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/CurrentSourceGenerator.cs index 84a26da9..7839e68b 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/CurrentSourceGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/CurrentSourceGenerator.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using SpiceSharp.Components; -using SpiceSharp.Simulations; -using SpiceSharpBehavioral.Parsers; using SpiceSharpParser.Common; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.ModelReaders.Netlist.Spice.Exceptions; @@ -138,11 +135,12 @@ private Component CreateCustomCurrentSource(string name, ParameterCollection par var valueParameter = (AssignmentParameter)parameters.Single(p => p is AssignmentParameter ap && ap.Name.ToLower() == "value"); var entity = new BehavioralCurrentSource(name); - entity.SetParameter>>("parser", (sim) => CreateParser(context, sim)); context.CreateNodes(entity, parameters); + var baseParameters = entity.ParameterSets.Get(); baseParameters.Expression = valueParameter.Value; baseParameters.SpicePropertyComparer = StringComparerProvider.Get(context.CaseSensitivity.IsFunctionNameCaseSensitive); + baseParameters.Parser = (sim) => CreateParser(context, sim); return entity; } @@ -152,13 +150,12 @@ private Component CreateCustomCurrentSource(string name, ParameterCollection par if (expressionParameter != null) { var entity = new BehavioralCurrentSource(name); - entity.SetParameter>>("parser", (sim) => CreateParser(context, sim)); - context.CreateNodes(entity, parameters); + var baseParameters = entity.ParameterSets.Get(); baseParameters.Expression = expressionParameter.Image; baseParameters.SpicePropertyComparer = StringComparerProvider.Get(context.CaseSensitivity.IsFunctionNameCaseSensitive); - + baseParameters.Parser = (sim) => CreateParser(context, sim); return entity; } } @@ -207,14 +204,13 @@ private Component CreateCustomCurrentSource(string name, ParameterCollection par if (nextParameter is ExpressionEqualParameter eep) { - var entity = new CurrentSource(name); + var entity = new BehavioralCurrentSource(name); context.CreateNodes(entity, parameters); - parameters = parameters.Skip(CurrentSource.CurrentSourcePinCount); - - var tableParameterName = name + "_table_variable"; - context.SetParameter(tableParameterName, eep.Expression); - string expression = ExpressionFactory.CreateTableExpression(tableParameterName, eep.Points); - context.SetParameter(entity, "dc", expression); + + var baseParameters = entity.ParameterSets.Get(); + baseParameters.Expression = ExpressionFactory.CreateTableExpression(eep.Expression, eep.Points); + baseParameters.SpicePropertyComparer = StringComparerProvider.Get(context.CaseSensitivity.IsFunctionNameCaseSensitive); + baseParameters.Parser = (sim) => CreateParser(context, sim); return entity; } else diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/SourceGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/SourceGenerator.cs index ccecaa0a..6df8f1b1 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/SourceGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/SourceGenerator.cs @@ -13,7 +13,7 @@ public abstract class SourceGenerator : ComponentGenerator { protected SimpleDerivativeParser CreateParser(IReadingContext context, Simulation simulation) { - var parser = Parsers.Expression.ExpressionParserHelpers.GetDeriveParser(context.SimulationExpressionContexts.GetContext(simulation), context, context.ReadingEvaluator, simulation); + var parser = Parsers.Expression.ExpressionParserHelpers.GetDeriveParser(context.SimulationExpressionContexts.GetContext(simulation), context, context.ReadingEvaluator, simulation, context.CaseSensitivity); return parser; } diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/VoltageSourceGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/VoltageSourceGenerator.cs index 91f590be..58b6b414 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/VoltageSourceGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/Sources/VoltageSourceGenerator.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using SpiceSharp.Components; -using SpiceSharp.Simulations; using SpiceSharpBehavioral.Components.BehavioralBehaviors; -using SpiceSharpBehavioral.Parsers; using SpiceSharpParser.Common; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.ModelReaders.Netlist.Spice.Exceptions; @@ -151,12 +148,11 @@ protected Component CreateCustomVoltageSource( { var entity = new BehavioralVoltageSource(name); context.CreateNodes(entity, parameters); - entity.SetParameter>>("parser", (Simulation sim) => CreateParser(context, sim), null); - var baseParameters = entity.ParameterSets.Get(); var valueParameter = (AssignmentParameter)parameters.Single(p => p is AssignmentParameter ap && ap.Name.ToLower() == "value"); baseParameters.Expression = valueParameter.Value; baseParameters.SpicePropertyComparer = StringComparerProvider.Get(context.CaseSensitivity.IsFunctionNameCaseSensitive); + baseParameters.Parser = (sim) => CreateParser(context, sim); return entity; } @@ -164,8 +160,8 @@ protected Component CreateCustomVoltageSource( if (parameters.Any(p => p is WordParameter ap && ap.Image.ToLower() == "value")) { var entity = new BehavioralVoltageSource(name); - entity.SetParameter>>("parser", (Simulation sim) => CreateParser(context, sim), null); context.CreateNodes(entity, parameters); + var baseParameters = entity.ParameterSets.Get(); var expressionParameter = parameters.FirstOrDefault(p => p is ExpressionParameter); if (expressionParameter != null) @@ -173,6 +169,7 @@ protected Component CreateCustomVoltageSource( baseParameters.Expression = expressionParameter.Image; } baseParameters.SpicePropertyComparer = StringComparerProvider.Get(context.CaseSensitivity.IsFunctionNameCaseSensitive); + baseParameters.Parser = (sim) => CreateParser(context, sim); return entity; } @@ -220,12 +217,14 @@ protected Component CreateCustomVoltageSource( if (nextParameter is ExpressionEqualParameter eep) { - var entity = new VoltageSource(name); + var entity = new BehavioralVoltageSource(name); context.CreateNodes(entity, parameters); - var tableParameterName = name + "_table_variable"; - context.SetParameter(tableParameterName, eep.Expression); - string expression = ExpressionFactory.CreateTableExpression(tableParameterName, eep.Points); - context.SetParameter(entity, "dc", expression); + + var baseParameters = entity.ParameterSets.Get(); + baseParameters.Parser = (sim) => CreateParser(context, sim); + baseParameters.Expression = ExpressionFactory.CreateTableExpression(eep.Expression, eep.Points); + baseParameters.SpicePropertyComparer = StringComparerProvider.Get(context.CaseSensitivity.IsFunctionNameCaseSensitive); + return entity; } else diff --git a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs index 5776c751..22cb9b6e 100644 --- a/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs +++ b/src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/EntityGenerators/Components/SubCircuitGenerator.cs @@ -6,6 +6,7 @@ using SpiceSharpBehavioral.Components.BehavioralBehaviors; using SpiceSharpParser.Common; using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.Common.Evaluation.Expressions; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Names; using SpiceSharpParser.ModelReaders.Netlist.Spice.Exceptions; @@ -118,7 +119,7 @@ private void CreateSubcircuitComponents(SubCircuit subCircuitDefinition, IReadin { foreach (Statement statement in subCircuitDefinition.Statements.Where(s => s is Component)) { - subCircuitContext.StatementsReader.Read((Component) statement, subCircuitContext); + subCircuitContext.StatementsReader.Read((Component)statement, subCircuitContext); var lastEntity = subCircuitContext.Result.Circuit.Last(); @@ -210,14 +211,15 @@ private ReadingContext CreateSubcircuitContext(string subcircuitFullName, string subCircuitDefiniton, subCktParameters, context.CaseSensitivity, - context.ReadingEvaluator); + context.ReadingEvaluator, + context); var subCircuitExpressionContext = context.ReadingExpressionContext.CreateChildContext(subcircuitFullName, true); var pp = new Dictionary>(); foreach (var sp in subcircuitParameters) { - pp[sp.Key] = ExpressionParserHelpers.GetExpressionParameters(sp.Value, subCircuitExpressionContext, context, false); + pp[sp.Key] = ExpressionParserHelpers.GetExpressionParameters(sp.Value, subCircuitExpressionContext, context,context.CaseSensitivity, false); } subCircuitExpressionContext.SetParameters(subcircuitParameters, pp); @@ -278,7 +280,7 @@ private ReadingContext CreateSubcircuitContext(string subcircuitFullName, string /// /// A dictionary of parameters. /// - private Dictionary CreateSubcircuitParameters(ExpressionContext rootExpressionContext, SubCircuit subCiruitDefiniton, List subcktParameters, SpiceNetlistCaseSensitivitySettings caseSettings, IEvaluator evaluator) + private Dictionary CreateSubcircuitParameters(ExpressionContext rootExpressionContext, SubCircuit subCiruitDefiniton, List subcktParameters, SpiceNetlistCaseSensitivitySettings caseSettings, IEvaluator evaluator, IReadingContext readingContext) { var result = new Dictionary(StringComparerProvider.Get(caseSettings.IsParameterNameCaseSensitive)); @@ -296,8 +298,7 @@ private Dictionary CreateSubcircuitParameters(ExpressionContext { if (parameterName == result[parameterName]) { - result[parameterName] = evaluator.EvaluateValueExpression(parameterName, rootExpressionContext) - .ToString(CultureInfo.InvariantCulture); + result[parameterName] = evaluator.Evaluate(new DynamicExpression(parameterName), rootExpressionContext,null, readingContext).ToString(CultureInfo.InvariantCulture); } } diff --git a/src/SpiceSharpParser/Parsers/Expression/ExpressionParser.cs b/src/SpiceSharpParser/Parsers/Expression/ExpressionParser.cs new file mode 100644 index 00000000..d1162c1d --- /dev/null +++ b/src/SpiceSharpParser/Parsers/Expression/ExpressionParser.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using SpiceSharp; +using SpiceSharpBehavioral.Parsers; +using SpiceSharpBehavioral.Parsers.Helper; +using SpiceSharpParser.Common; +using SpiceSharpParser.ModelReaders.Netlist.Spice; + +namespace SpiceSharpParser.Parsers.Expression +{ + public class ExpressionParser : SimpleDerivativeParser + { + /// + /// The default functions. + /// + public Dictionary DefaultFunctions { get; set; } + + public ExpressionParser(SpiceNetlistCaseSensitivitySettings caseSensitivitySettings) + { + bool isFunctionCaseSesitive = caseSensitivitySettings?.IsFunctionNameCaseSensitive ?? false; + + DefaultFunctions = + new Dictionary( + StringComparerProvider.Get(isFunctionCaseSesitive)) + { + { "Exp", SimpleDerivativeParserHelper.ApplyExp }, + { "Log", SimpleDerivativeParserHelper.ApplyLog }, + { "Pow", SimpleDerivativeParserHelper.ApplyPow }, + { "Log10", SimpleDerivativeParserHelper.ApplyLog10 }, + { "Sqrt", SimpleDerivativeParserHelper.ApplySqrt }, + { "Sin", SimpleDerivativeParserHelper.ApplySin }, + { "Cos", ApplyCos }, + { "Tan", ApplyTan }, + { "Asin", SimpleDerivativeParserHelper.ApplyAsin }, + { "Acos", SimpleDerivativeParserHelper.ApplyAcos }, + { "Atan", SimpleDerivativeParserHelper.ApplyAtan }, + { "Abs", SimpleDerivativeParserHelper.ApplyAbs }, + { "Round", SimpleDerivativeParserHelper.ApplyRound }, + { "Min", SimpleDerivativeParserHelper.ApplyMin }, + { "Max", SimpleDerivativeParserHelper.ApplyMax } + }; + + FunctionFound += ExpressionParser_FunctionFound; + } + + private void ExpressionParser_FunctionFound(object sender, FunctionFoundEventArgs>> e) + { + if (DefaultFunctions.TryGetValue(e.Name, out var function)) + { + var arguments = new Derivatives>[e.ArgumentCount]; + for (var i = 0; i < e.ArgumentCount; i++) + arguments[i] = e[i]; + e.Result = function?.Invoke(arguments); + } + } + + /// + /// Applies the cosine. + /// + /// The arguments. + /// The cosine result. + private static Derivatives> ApplyCos(Derivatives>[] arguments) + { + arguments.ThrowIfNot(nameof(arguments), 1); + var arg = arguments[0]; + var result = new DoubleDerivatives(arg.Count); + var a0 = arg[0]; + result[0] = () => Math.Cos(a0()); + + // Apply the chain rule + for (var i = 1; i < arg.Count; i++) + { + if (arg[i] != null) + { + var ai = arg[i]; + result[i] = () => -Math.Sin(a0()) * ai(); + } + } + return result; + } + + + /// + /// Applies the tangent. + /// + /// The arguments. + /// The tangent result. + private static Derivatives> ApplyTan(Derivatives>[] arguments) + { + arguments.ThrowIfNot(nameof(arguments), 1); + var arg = arguments[0]; + var result = new DoubleDerivatives(arg.Count); + var a0 = arg[0]; + result[0] = () => Math.Tan(a0()); + + // Apply the chain rule + for (var i = 1; i < arg.Count; i++) + { + if (arg[i] != null) + { + var ai = arg[i]; + result[i] = () => + { + var tmp = Math.Cos(a0()); + return ai() / tmp / tmp; + }; + } + } + return result; + } + } +} diff --git a/src/SpiceSharpParser/Parsers/Expression/ExpressionParserHelpers.cs b/src/SpiceSharpParser/Parsers/Expression/ExpressionParserHelpers.cs index 8fb64744..b6b50213 100644 --- a/src/SpiceSharpParser/Parsers/Expression/ExpressionParserHelpers.cs +++ b/src/SpiceSharpParser/Parsers/Expression/ExpressionParserHelpers.cs @@ -5,6 +5,7 @@ using SpiceSharpBehavioral.Parsers; using SpiceSharpBehavioral.Parsers.Helper; using SpiceSharpParser.Common.Evaluation; +using SpiceSharpParser.ModelReaders.Netlist.Spice; using SpiceSharpParser.ModelReaders.Netlist.Spice.Context; using SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.Controls.Exporters; using SpiceSharpParser.Models.Netlist.Spice.Objects; @@ -16,14 +17,14 @@ public class ExpressionParserHelpers { public static double GetExpressionValue(string expression, ExpressionContext context, IEvaluator evaluator, Simulation simulation, IReadingContext readingContext, bool @throw = true) { - var parser = GetDeriveParser(context, readingContext, evaluator, simulation, @throw); + var parser = GetDeriveParser(context, readingContext, evaluator, simulation, readingContext?.CaseSensitivity, @throw); var derivatives = parser.Parse(expression); return derivatives[0](); } - public static List GetExpressionParameters(string expression, ExpressionContext context, IReadingContext readingContext, bool @throw) + public static List GetExpressionParameters(string expression, ExpressionContext context, IReadingContext readingContext, SpiceNetlistCaseSensitivitySettings caseSettings, bool @throw) { - var parser = GetDeriveParser(context, readingContext, null, null, @throw); + var parser = GetDeriveParser(context, readingContext, null, null, caseSettings, @throw); var parameters = new List(); parser.VariableFound += (sender, e) => { @@ -38,58 +39,17 @@ public static List GetExpressionParameters(string expression, Expression return parameters; } - public static SimpleDerivativeParser GetDeriveParser(ExpressionContext context, IReadingContext readingContext, IEvaluator evaluator, Simulation simulation, bool @throw = true) + public static SimpleDerivativeParser GetDeriveParser(ExpressionContext context, IReadingContext readingContext, IEvaluator evaluator, Simulation simulation, SpiceNetlistCaseSensitivitySettings caseSettings, bool @throw = true) { - var parser = new SimpleDerivativeParser(); - parser.RegisterDefaultFunctions(); - - parser.VariableFound += (sender, args) => - { - if (context.Arguments.Any(a => a.Key == args.Name)) - { - var d = new DoubleDerivatives(2); - d[0] = () => context.Arguments.First(a => a.Key == args.Name).Value.Evaluate(evaluator, context,simulation, readingContext); - d[1] = () => 1; - args.Result = d; - return; - } - - if (context.Parameters.ContainsKey(args.Name)) - { - var d = new DoubleDerivatives(2); - d[0] = () => context.Parameters[args.Name].Evaluate(evaluator, context, simulation, readingContext); - d[1] = () => 0; - args.Result = d; - return; - } - - if (readingContext != null) - { - var readingExpressionContext = readingContext.ReadingExpressionContext; - - if (readingExpressionContext.Parameters.ContainsKey(args.Name)) - { - var d = new DoubleDerivatives(2); - d[0] = () => readingExpressionContext.Parameters[args.Name].Evaluate(evaluator, context,simulation, readingContext); - d[1] = () => 0; - args.Result = d; - return; - } - } - - if (@throw) - { - throw new UnknownParameterException(); - } - else - { - var d = new DoubleDerivatives(1); - d[0] = () => double.NaN; - args.Result = d; - } - }; - parser.FunctionFound += GetFunctionFound(context, readingContext, evaluator, simulation); - parser.SpicePropertyFound += (sender, arg) => + var parser = new ExpressionParser(caseSettings); + parser.VariableFound += OnVariableFound(context, readingContext, evaluator, simulation, @throw); + parser.FunctionFound += OnFunctionFound(context, readingContext, evaluator, simulation); + parser.SpicePropertyFound += OnSpicePropertyFound(context, readingContext, evaluator, simulation); + return parser; + } + private static EventHandler> OnSpicePropertyFound(ExpressionContext context, IReadingContext readingContext, IEvaluator evaluator, Simulation simulation) + { + return (sender, arg) => { if (arg is SimpleDerivativePropertyEventArgs argTyped) { @@ -114,12 +74,14 @@ public static SimpleDerivativeParser GetDeriveParser(ExpressionContext context, if (context.Arguments.ContainsKey(argument)) { - var argumentValue = context.Arguments[argument].Evaluate(evaluator, context, simulation, readingContext); + var expression = context.Arguments[argument]; + var argumentValue = evaluator.Evaluate(expression, context, simulation, readingContext); vectorParameter.Elements.Add(new WordParameter(((int)argumentValue).ToString())); } else if (context.Parameters.ContainsKey(argument)) { - var argumentValue = context.Parameters[argument].Evaluate(evaluator, context, simulation, readingContext); + var expression = context.Parameters[argument]; + var argumentValue = evaluator.Evaluate(expression, context, simulation, readingContext); vectorParameter.Elements.Add(new WordParameter(((int)argumentValue).ToString())); } else @@ -168,10 +130,73 @@ public static SimpleDerivativeParser GetDeriveParser(ExpressionContext context, arg.Apply(() => export.Extract()); }; - return parser; } - private static EventHandler>>> GetFunctionFound(ExpressionContext context, IReadingContext readingContext, IEvaluator evaluator, Simulation simulation) + private static EventHandler>>> OnVariableFound(ExpressionContext context, IReadingContext readingContext, IEvaluator evaluator, Simulation simulation, bool @throw) + { + return (sender, args) => + { + if (context.Arguments.Any(a => a.Key == args.Name)) + { + var d = new DoubleDerivatives(2); + d[0] = () => + { + var expression = context.Arguments.First(a => a.Key == args.Name).Value; + var value = evaluator.Evaluate(expression, context, simulation, readingContext); + return value; + }; + d[1] = () => 1; + args.Result = d; + return; + } + + if (context.Parameters.ContainsKey(args.Name)) + { + var d = new DoubleDerivatives(2); + d[0] = () => + { + var parameter = context.Parameters[args.Name]; + var value = evaluator.Evaluate(parameter, context, simulation, readingContext); + return value; + }; + d[1] = () => 0; + args.Result = d; + return; + } + + if (readingContext != null) + { + var readingExpressionContext = readingContext.ReadingExpressionContext; + + if (readingExpressionContext.Parameters.ContainsKey(args.Name)) + { + var d = new DoubleDerivatives(2); + d[0] = () => + { + var expression = readingExpressionContext.Parameters[args.Name]; + var value = evaluator.Evaluate(expression, context, simulation, readingContext); + return value; + }; + d[1] = () => 0; + args.Result = d; + return; + } + } + + if (@throw) + { + throw new UnknownParameterException(); + } + else + { + var d = new DoubleDerivatives(1); + d[0] = () => double.NaN; + args.Result = d; + } + }; + } + + private static EventHandler>>> OnFunctionFound(ExpressionContext context, IReadingContext readingContext, IEvaluator evaluator, Simulation simulation) { return (sender, args) => { @@ -366,7 +391,7 @@ private static double GetDerivativeValue(ExpressionContext context, IEvaluator e public static bool HaveSpiceProperties(string expression, ExpressionContext context, ReadingContext readingContext, bool b) { bool present = false; - var parser = GetDeriveParser(context, readingContext, null, null); + var parser = GetDeriveParser(context, readingContext, null, null, readingContext.CaseSensitivity); parser.SpicePropertyFound += (sender, e) => { present = true; @@ -377,10 +402,10 @@ public static bool HaveSpiceProperties(string expression, ExpressionContext cont return present; } - public static bool HaveFunctions(string expression, ExpressionContext context, ReadingContext readingContext, bool v) + public static bool HaveFunctions(string expression, ExpressionContext context, ReadingContext readingContext) { bool present = false; - var parser = GetDeriveParser(context, readingContext, null, null); + var parser = GetDeriveParser(context, readingContext, null, null, readingContext.CaseSensitivity); parser.FunctionFound += (sender, e) => { present = true;