1+ using OrdinaryDiffEq, RecursiveArrayTools, Test
2+
3+ @testset " ODE Solution recursivecopy tests" begin
4+
5+ @testset " Basic ODE solution copying" begin
6+ # Define a simple ODE system
7+ function simple_ode! (du, u, p, t)
8+ du[1 ] = - 0.5 * u[1 ]
9+ du[2 ] = 0.3 * u[2 ]
10+ end
11+
12+ u0 = [1.0 , 2.0 ]
13+ tspan = (0.0 , 2.0 )
14+ prob = ODEProblem (simple_ode!, u0, tspan)
15+ sol = solve (prob, Tsit5 (), saveat= 0.5 )
16+
17+ # Test that we can copy the solution
18+ copied_sol = recursivecopy (sol)
19+
20+ # Verify the solution structure is preserved
21+ @test typeof (copied_sol) == typeof (sol)
22+ @test copied_sol. t == sol. t
23+ @test copied_sol. u == sol. u
24+ @test copied_sol. retcode == sol. retcode
25+
26+ # Verify that arrays are independent copies
27+ @test copied_sol != = sol
28+ @test copied_sol. u != = sol. u
29+ @test copied_sol. t != = sol. t
30+
31+ # Test that modifying one doesn't affect the other
32+ if length (copied_sol. u) > 0
33+ original_value = sol. u[1 ][1 ]
34+ copied_sol. u[1 ][1 ] = 999.0
35+ @test sol. u[1 ][1 ] == original_value # Original should be unchanged
36+ end
37+ end
38+
39+ @testset " ArrayPartition ODE solution copying" begin
40+ # Use the Lorenz system from the existing tests
41+ function lorenz! (du, u, p, t)
42+ du. x[1 ][1 ] = 10.0 * (u. x[2 ][1 ] - u. x[1 ][1 ])
43+ du. x[1 ][2 ] = u. x[1 ][1 ] * (28.0 - u. x[2 ][1 ]) - u. x[1 ][2 ]
44+ du. x[2 ][1 ] = u. x[1 ][1 ] * u. x[1 ][2 ] - (8 / 3 ) * u. x[2 ][1 ]
45+ end
46+
47+ u0 = ArrayPartition ([1.0 , 0.0 ], [0.0 ])
48+ tspan = (0.0 , 1.0 )
49+ prob = ODEProblem (lorenz!, u0, tspan)
50+ sol = solve (prob, Tsit5 (), saveat= 0.2 )
51+
52+ # Test that we can copy the ArrayPartition-based solution
53+ copied_sol = recursivecopy (sol)
54+
55+ # Verify solution structure
56+ @test typeof (copied_sol) == typeof (sol)
57+ @test copied_sol. t == sol. t
58+ @test length (copied_sol. u) == length (sol. u)
59+
60+ # Verify ArrayPartition structure is preserved
61+ for i in eachindex (sol. u)
62+ @test copied_sol. u[i] isa ArrayPartition
63+ @test copied_sol. u[i]. x[1 ] == sol. u[i]. x[1 ]
64+ @test copied_sol. u[i]. x[2 ] == sol. u[i]. x[2 ]
65+
66+ # Verify independence
67+ @test copied_sol. u[i] != = sol. u[i]
68+ @test copied_sol. u[i]. x[1 ] != = sol. u[i]. x[1 ]
69+ @test copied_sol. u[i]. x[2 ] != = sol. u[i]. x[2 ]
70+ end
71+ end
72+
73+ @testset " Struct-based parameter copying in ODE" begin
74+ # Create an ODE with struct-based parameters to test our struct copying
75+ struct ODEParams
76+ decay_rate:: Float64
77+ growth_rate:: Float64
78+ coefficients:: Vector{Float64}
79+ end
80+
81+ function parametric_ode! (du, u, params:: ODEParams , t)
82+ du[1 ] = - params. decay_rate * u[1 ] + params. coefficients[1 ]
83+ du[2 ] = params. growth_rate * u[2 ] + params. coefficients[2 ]
84+ end
85+
86+ params = ODEParams (0.5 , 0.3 , [0.1 , 0.2 ])
87+ u0 = [1.0 , 2.0 ]
88+ tspan = (0.0 , 1.0 )
89+ prob = ODEProblem (parametric_ode!, u0, tspan, params)
90+ sol = solve (prob, Tsit5 (), saveat= 0.5 )
91+
92+ # Test copying the solution (which contains the struct parameters)
93+ copied_sol = recursivecopy (sol)
94+
95+ # Verify parameter struct is copied correctly
96+ @test copied_sol. prob. p isa ODEParams
97+ @test copied_sol. prob. p. decay_rate == sol. prob. p. decay_rate
98+ @test copied_sol. prob. p. growth_rate == sol. prob. p. growth_rate
99+ @test copied_sol. prob. p. coefficients == sol. prob. p. coefficients
100+
101+ # Verify independence
102+ @test copied_sol. prob. p != = sol. prob. p
103+ @test copied_sol. prob. p. coefficients != = sol. prob. p. coefficients
104+
105+ # Test that modifying copied parameters doesn't affect original
106+ copied_sol. prob. p. coefficients[1 ] = 999.0
107+ @test sol. prob. p. coefficients[1 ] == 0.1 # Original unchanged
108+ end
109+
110+ println (" All ODE solution recursivecopy tests completed successfully!" )
111+ end
0 commit comments