|
1 | 1 | using ModelingToolkit, OrdinaryDiffEq, NonlinearSolve, Test
|
| 2 | +using SymbolicIndexingInterface |
2 | 3 | using ModelingToolkit: t_nounits as t, D_nounits as D
|
3 | 4 |
|
4 | 5 | @parameters g
|
@@ -576,3 +577,132 @@ sol = solve(oprob_2nd_order_2, Rosenbrock23()) # retcode: Success
|
576 | 577 | sol = solve(prob, Tsit5(), reltol = 1e-4)
|
577 | 578 | @test all(sol(1.0, idxs = sys.x) .≈ +exp(1)) && all(sol(1.0, idxs = sys.y) .≈ -exp(1))
|
578 | 579 | end
|
| 580 | + |
| 581 | +@testset "Initialization of parameters" begin |
| 582 | + function test_parameter(prob, sym, val, initialval = zero(val)) |
| 583 | + @test prob.ps[sym] ≈ initialval |
| 584 | + @test init(prob, Tsit5()).ps[sym] ≈ val |
| 585 | + @test solve(prob, Tsit5()).ps[sym] ≈ val |
| 586 | + end |
| 587 | + function test_initializesystem(sys, u0map, pmap, p, equation) |
| 588 | + isys = ModelingToolkit.generate_initializesystem( |
| 589 | + sys; u0map, pmap, guesses = ModelingToolkit.guesses(sys)) |
| 590 | + @test is_variable(isys, p) |
| 591 | + @test equation in equations(isys) || (0 ~ -equation.rhs) in equations(isys) |
| 592 | + end |
| 593 | + @variables x(t) y(t) |
| 594 | + @parameters p q |
| 595 | + u0map = Dict(x => 1.0, y => 1.0) |
| 596 | + pmap = Dict() |
| 597 | + pmap[q] = 1.0 |
| 598 | + # `missing` default, equation from ODEProblem |
| 599 | + @mtkbuild sys = ODESystem( |
| 600 | + [D(x) ~ x * q, D(y) ~ y * p], t; defaults = [p => missing], guesses = [p => 1.0]) |
| 601 | + pmap[p] = 2q |
| 602 | + prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap) |
| 603 | + test_parameter(prob, p, 2.0) |
| 604 | + # `missing` default, provided guess |
| 605 | + @mtkbuild sys = ODESystem( |
| 606 | + [D(x) ~ x, p ~ x + y], t; defaults = [p => missing], guesses = [p => 0.0]) |
| 607 | + prob = ODEProblem(sys, u0map, (0.0, 1.0)) |
| 608 | + test_parameter(prob, p, 2.0) |
| 609 | + test_initializesystem(sys, u0map, pmap, p, 0 ~ p - x - y) |
| 610 | + |
| 611 | + # `missing` to ODEProblem, equation from default |
| 612 | + @mtkbuild sys = ODESystem( |
| 613 | + [D(x) ~ x * q, D(y) ~ y * p], t; defaults = [p => 2q], guesses = [p => 1.0]) |
| 614 | + pmap[p] = missing |
| 615 | + prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap) |
| 616 | + test_parameter(prob, p, 2.0) |
| 617 | + test_initializesystem(sys, u0map, pmap, p, 0 ~ 2q - p) |
| 618 | + test_parameter(prob2, p, 2.0) |
| 619 | + # `missing` to ODEProblem, provided guess |
| 620 | + @mtkbuild sys = ODESystem( |
| 621 | + [D(x) ~ x, p ~ x + y], t; guesses = [p => 0.0]) |
| 622 | + prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap) |
| 623 | + test_parameter(prob, p, 2.0) |
| 624 | + test_initializesystem(sys, u0map, pmap, p, 0 ~ x + y - p) |
| 625 | + |
| 626 | + # No `missing`, default and guess |
| 627 | + @mtkbuild sys = ODESystem( |
| 628 | + [D(x) ~ x * q, D(y) ~ y * p], t; defaults = [p => 2q], guesses = [p => 0.0]) |
| 629 | + delete!(pmap, p) |
| 630 | + prob = ODEProblem(sys, u0map, (0.0, 1.0), pmap) |
| 631 | + test_parameter(prob, p, 2.0) |
| 632 | + test_initializesystem(sys, u0map, pmap, p, 0 ~ 2q - p) |
| 633 | + |
| 634 | + # Should not be solved for: |
| 635 | + |
| 636 | + # ODEProblem value with guess, no `missing` |
| 637 | + @mtkbuild sys = ODESystem([D(x) ~ x * q, D(y) ~ y * p], t; guesses = [p => 0.0]) |
| 638 | + _pmap = merge(pmap, Dict(p => 3q)) |
| 639 | + prob = ODEProblem(sys, u0map, (0.0, 1.0), _pmap) |
| 640 | + @test prob.ps[p] ≈ 3.0 |
| 641 | + @test prob.f.initializeprob === nothing |
| 642 | + # Default overridden by ODEProblem, guess provided |
| 643 | + @mtkbuild sys = ODESystem( |
| 644 | + [D(x) ~ q * x, D(y) ~ y * p], t; defaults = [p => 2q], guesses = [p => 1.0]) |
| 645 | + prob = ODEProblem(sys, u0map, (0.0, 1.0), _pmap) |
| 646 | + @test prob.ps[p] ≈ 3.0 |
| 647 | + @test prob.f.initializeprob === nothing |
| 648 | + |
| 649 | + @mtkbuild sys = ODESystem([D(x) ~ x, p ~ x + y], t; guesses = [p => 0.0]) |
| 650 | + @test_throws ModelingToolkit.MissingParametersError ODEProblem( |
| 651 | + sys, [x => 1.0, y => 1.0], (0.0, 1.0)) |
| 652 | + |
| 653 | + @testset "Null system" begin |
| 654 | + @variables x(t) y(t) s(t) |
| 655 | + @parameters x0 y0 |
| 656 | + @mtkbuild sys = ODESystem([x ~ x0, y ~ y0, s ~ x + y], t; guesses = [y0 => 0.0]) |
| 657 | + prob = ODEProblem(sys, [s => 1.0], (0.0, 1.0), [x0 => 0.3, y0 => missing]) |
| 658 | + test_parameter(prob, y0, 0.7) |
| 659 | + end |
| 660 | + |
| 661 | + using ModelingToolkitStandardLibrary.Mechanical.TranslationalModelica: Fixed, Mass, |
| 662 | + Spring, Force, |
| 663 | + Damper |
| 664 | + using ModelingToolkitStandardLibrary.Mechanical: TranslationalModelica as TM |
| 665 | + using ModelingToolkitStandardLibrary.Blocks: Constant |
| 666 | + |
| 667 | + @named mass = TM.Mass(; m = 1.0, s = 1.0, v = 0.0, a = 0.0) |
| 668 | + @named fixed = Fixed(; s0 = 0.0) |
| 669 | + @named spring = Spring(; c = 2.0, s_rel0 = nothing) |
| 670 | + @named gravity = Force() |
| 671 | + @named constant = Constant(; k = 9.81) |
| 672 | + @named damper = TM.Damper(; d = 0.1) |
| 673 | + @mtkbuild sys = ODESystem( |
| 674 | + [connect(fixed.flange, spring.flange_a), connect(spring.flange_b, mass.flange_a), |
| 675 | + connect(mass.flange_a, gravity.flange), connect(constant.output, gravity.f), |
| 676 | + connect(fixed.flange, damper.flange_a), connect(damper.flange_b, mass.flange_a)], |
| 677 | + t; |
| 678 | + systems = [fixed, spring, mass, gravity, constant, damper], |
| 679 | + guesses = [spring.s_rel0 => 1.0]) |
| 680 | + prob = ODEProblem(sys, [], (0.0, 1.0), [spring.s_rel0 => missing]) |
| 681 | + test_parameter(prob, spring.s_rel0, -3.905) |
| 682 | +end |
| 683 | + |
| 684 | +@testset "Update initializeprob parameters" begin |
| 685 | + @variables x(t) y(t) |
| 686 | + @parameters p q |
| 687 | + @mtkbuild sys = ODESystem( |
| 688 | + [D(x) ~ x, p ~ x + y], t; guesses = [x => 0.0, p => 0.0]) |
| 689 | + prob = ODEProblem(sys, [y => 1.0], (0.0, 1.0), [p => 3.0]) |
| 690 | + @test prob.f.initializeprob.ps[p] ≈ 3.0 |
| 691 | + @test init(prob, Tsit5())[x] ≈ 2.0 |
| 692 | + prob.ps[p] = 2.0 |
| 693 | + @test prob.f.initializeprob.ps[p] ≈ 3.0 |
| 694 | + @test init(prob, Tsit5())[x] ≈ 1.0 |
| 695 | + ModelingToolkit.defaults(prob.f.sys)[p] = missing |
| 696 | +end |
| 697 | + |
| 698 | +@testset "Equations for dependent parameters" begin |
| 699 | + @variables x(t) |
| 700 | + @parameters p q=5 r |
| 701 | + @mtkbuild sys = ODESystem( |
| 702 | + D(x) ~ 2x + r, t; parameter_dependencies = [r ~ p + 2q, q ~ p + 3], |
| 703 | + guesses = [p => 1.0]) |
| 704 | + prob = ODEProblem(sys, [x => 1.0], (0.0, 1.0), [p => missing]) |
| 705 | + @test length(equations(ModelingToolkit.get_parent(prob.f.initializeprob.f.sys))) == 4 |
| 706 | + integ = init(prob, Tsit5()) |
| 707 | + @test integ.ps[p] ≈ 2 |
| 708 | +end |
0 commit comments