|
| 1 | +using ModelingToolkit |
| 2 | +using NonlinearSolve, SCCNonlinearSolve |
| 3 | +using SciMLBase, Symbolics |
| 4 | +using LinearAlgebra, Test |
| 5 | + |
| 6 | +@testset "Trivial case" begin |
| 7 | + function f!(du, u, p) |
| 8 | + du[1] = cos(u[2]) - u[1] |
| 9 | + du[2] = sin(u[1] + u[2]) + u[2] |
| 10 | + du[3] = 2u[4] + u[3] + 1.0 |
| 11 | + du[4] = u[5]^2 + u[4] |
| 12 | + du[5] = u[3]^2 + u[5] |
| 13 | + du[6] = u[1] + u[2] + u[3] + u[4] + u[5] + 2.0u[6] + 2.5u[7] + 1.5u[8] |
| 14 | + du[7] = u[1] + u[2] + u[3] + 2.0u[4] + u[5] + 4.0u[6] - 1.5u[7] + 1.5u[8] |
| 15 | + du[8] = u[1] + 2.0u[2] + 3.0u[3] + 5.0u[4] + 6.0u[5] + u[6] - u[7] - u[8] |
| 16 | + end |
| 17 | + prob = NonlinearProblem(f!, zeros(8)) |
| 18 | + @variables u[1:8] [irreducible = true] |
| 19 | + eqs = Any[0 for _ in 1:8] |
| 20 | + f!(eqs, u, nothing) |
| 21 | + eqs = 0 .~ eqs |
| 22 | + @named model = NonlinearSystem(eqs) |
| 23 | + @test_throws ["simplified", "required"] SCCNonlinearProblem(model, []) |
| 24 | + _model = structural_simplify(model; split = false) |
| 25 | + @test_throws ["not compatible"] SCCNonlinearProblem(_model, []) |
| 26 | + model = structural_simplify(model) |
| 27 | + sccprob = SCCNonlinearProblem(model, [u => zeros(8)]) |
| 28 | + sol1 = solve(prob, NewtonRaphson()) |
| 29 | + sol2 = solve(sccprob, NewtonRaphson()) |
| 30 | + @test SciMLBase.successful_retcode(sol1) |
| 31 | + @test SciMLBase.successful_retcode(sol2) |
| 32 | + @test sol1.u ≈ sol2.u |
| 33 | +end |
| 34 | + |
| 35 | +@testset "With parameters" begin |
| 36 | + function f!(du, u, (p1, p2), t) |
| 37 | + x = (*)(p1[4], u[1]) |
| 38 | + y = (*)(p1[4], (+)(0.1016, (*)(-1, u[1]))) |
| 39 | + z1 = ifelse((<)(p2[1], 0), |
| 40 | + (*)((*)(457896.07999999996, p1[2]), sqrt((*)(1.1686468413521012e-5, p1[3]))), |
| 41 | + 0) |
| 42 | + z2 = ifelse((>)(p2[1], 0), |
| 43 | + (*)((*)((*)(0.58, p1[2]), sqrt((*)(1//86100, p1[3]))), u[4]), |
| 44 | + 0) |
| 45 | + z3 = ifelse((>)(p2[1], 0), |
| 46 | + (*)((*)(457896.07999999996, p1[2]), sqrt((*)(1.1686468413521012e-5, p1[3]))), |
| 47 | + 0) |
| 48 | + z4 = ifelse((<)(p2[1], 0), |
| 49 | + (*)((*)((*)(0.58, p1[2]), sqrt((*)(1//86100, p1[3]))), u[5]), |
| 50 | + 0) |
| 51 | + du[1] = p2[1] |
| 52 | + du[2] = (+)(z1, (*)(-1, z2)) |
| 53 | + du[3] = (+)(z3, (*)(-1, z4)) |
| 54 | + du[4] = (+)((*)(-1, u[2]), (*)((*)(1//86100, y), u[4])) |
| 55 | + du[5] = (+)((*)(-1, u[3]), (*)((*)(1//86100, x), u[5])) |
| 56 | + end |
| 57 | + p = ([0.04864391799335977, 7.853981633974484e-5, 1.4034843205574914, 0.018241469247509915, 300237.05, 9.226186337232914], [0.0508]) |
| 58 | + u0 = [0.0, 0.0, 0.0, 789476.0, 101325.0] |
| 59 | + tspan = (0.0, 1.0) |
| 60 | + mass_matrix = [1.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0] |
| 61 | + |
| 62 | + function nlf(u1, (u0, p)) |
| 63 | + resid = Any[0 for _ in u0] |
| 64 | + f!(resid, u1, p, 0.0) |
| 65 | + return mass_matrix*(u1 - u0) - dt*resid |
| 66 | + end |
| 67 | + |
| 68 | + prob = NonlinearProblem(nlf, u0, (u0, p)) |
| 69 | + @test_throws Exception solve(prob, SimpleNewtonRaphson(), abstol = 1e-9) |
| 70 | + sol = solve(prob, TrustRegion(); abstol = 1e-9) |
| 71 | + |
| 72 | + @variables u[1:5] [irreducible = true] |
| 73 | + @parameters p1[1:6] p2 |
| 74 | + eqs = 0 .~ collect(nlf(u, (u0, (p1, p2)))) |
| 75 | + @mtkbuild sys = NonlinearSystem(eqs, [u], [p1, p2]) |
| 76 | + sccprob = SCCNonlinearProblem(sys, [u => u0], [p1 => p[1], p2 => p[2][]]) |
| 77 | + sccsol = solve(sccprob, SimpleNewtonRaphson(); abstol = 1e-9) |
| 78 | + @test SciMLBase.successful_retcode(sccsol) |
| 79 | + @test norm(sccsol.resid) < norm(sol.resid) |
| 80 | +end |
| 81 | + |
| 82 | +@testset "Transistor amplifier" begin |
| 83 | + C = [k * 1e-6 for k in 1:5] |
| 84 | + Ub = 6 |
| 85 | + UF = 0.026 |
| 86 | + α = 0.99 |
| 87 | + β = 1e-6 |
| 88 | + R0 = 1000 |
| 89 | + R = 9000 |
| 90 | + Ue(t) = 0.1 * sin(200 * π * t) |
| 91 | + |
| 92 | + function transamp(out, du, u, p, t) |
| 93 | + g(x) = 1e-6 * (exp(x / 0.026) - 1) |
| 94 | + y1, y2, y3, y4, y5, y6, y7, y8 = u |
| 95 | + out[1] = -Ue(t) / R0 + y1 / R0 + C[1] * du[1] - C[1] * du[2] |
| 96 | + out[2] = -Ub / R + y2 * 2 / R - (α - 1) * g(y2 - y3) - C[1] * du[1] + C[1] * du[2] |
| 97 | + out[3] = -g(y2 - y3) + y3 / R + C[2] * du[3] |
| 98 | + out[4] = -Ub / R + y4 / R + α * g(y2 - y3) + C[3] * du[4] - C[3] * du[5] |
| 99 | + out[5] = -Ub / R + y5 * 2 / R - (α - 1) * g(y5 - y6) - C[3] * du[4] + C[3] * du[5] |
| 100 | + out[6] = -g(y5 - y6) + y6 / R + C[4] * du[6] |
| 101 | + out[7] = -Ub / R + y7 / R + α * g(y5 - y6) + C[5] * du[7] - C[5] * du[8] |
| 102 | + out[8] = y8 / R - C[5] * du[7] + C[5] * du[8] |
| 103 | + end |
| 104 | + |
| 105 | + u0 = [0, Ub / 2, Ub / 2, Ub, Ub / 2, Ub / 2, Ub, 0] |
| 106 | + du0 = [ |
| 107 | + 51.338775, |
| 108 | + 51.338775, |
| 109 | + -Ub / (2 * (C[2] * R)), |
| 110 | + -24.9757667, |
| 111 | + -24.9757667, |
| 112 | + -Ub / (2 * (C[4] * R)), |
| 113 | + -10.00564453, |
| 114 | + -10.00564453 |
| 115 | + ] |
| 116 | + daeprob = DAEProblem(transamp, du0, u0, (0.0, 0.1)) |
| 117 | + daesol = solve(daeprob, DImplicitEuler()) |
| 118 | + |
| 119 | + t0 = daesol.t[5] |
| 120 | + t1 = daesol.t[6] |
| 121 | + u0 = daesol.u[5] |
| 122 | + u1 = daesol.u[6] |
| 123 | + dt = t1 - t0 |
| 124 | + |
| 125 | + @variables y(t)[1:8] |
| 126 | + eqs = Any[0 for _ in 1:8] |
| 127 | + transamp(eqs, collect(D(y)), y, nothing, t) |
| 128 | + eqs = 0 .~ eqs |
| 129 | + subrules = Dict(Symbolics.unwrap(D(y[i])) => ((y[i] - u0[i]) / dt) for i in 1:8) |
| 130 | + eqs = substitute.(eqs, (subrules,)) |
| 131 | + @mtkbuild sys = NonlinearSystem(eqs) |
| 132 | + prob = NonlinearProblem(sys, [y => u0], [t => t0]) |
| 133 | + sol = solve(prob, NewtonRaphson(); abstol = 1e-12) |
| 134 | + |
| 135 | + sccprob = SCCNonlinearProblem(sys, [y => u0], [t => t0]); |
| 136 | + sccsol = solve(sccprob, NewtonRaphson(); abstol = 1e-12) |
| 137 | + |
| 138 | + @test sol.u ≈ sccsol.u atol = 1e-10 |
| 139 | +end |
| 140 | + |
0 commit comments