Skip to content

Commit f1b20aa

Browse files
committed
test(solve): add test_solve_modes.jl for integration testing of solve modes
- Added to test explicit and descriptive modes on a real problem (Beam). - Limited iterations to 0 to ensure fast execution while verifying correct routing and return types. - Follows Separation of Concerns by isolating these end-to-end mode tests from unit and canonical tests.
1 parent 18b3dac commit f1b20aa

1 file changed

Lines changed: 164 additions & 0 deletions

File tree

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
module TestSolveModes
2+
3+
import Test
4+
import OptimalControl
5+
import CTDirect
6+
import CTSolvers
7+
8+
# Import display module (DIP)
9+
include(joinpath(@__DIR__, "..", "..", "helpers", "print_utils.jl"))
10+
using .TestPrintUtils
11+
12+
# Load solver extensions
13+
import NLPModelsIpopt
14+
import MadNLP
15+
16+
# Include shared test problems
17+
include(joinpath(@__DIR__, "..", "..", "problems", "TestProblems.jl"))
18+
using .TestProblems
19+
20+
const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true
21+
const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true
22+
23+
# Objective tolerance
24+
const OBJ_RTOL = 1e-2
25+
26+
function test_solve_modes()
27+
Test.@testset "Solve Modes (Explicit/Descriptive)" verbose = VERBOSE showtiming = SHOWTIMING begin
28+
29+
# Initialize statistics
30+
total_tests = 0
31+
passed_tests = 0
32+
total_start_time = time()
33+
34+
# Header
35+
if VERBOSE
36+
# Custom header for modes
37+
println("\n" * " "^4 * "SOLVE MODES (Layer 1 -> 2 -> 3)")
38+
print_test_header(false)
39+
end
40+
41+
# Problem to test (Beam is a good representative)
42+
pb = Beam()
43+
44+
# ----------------------------------------------------------------
45+
# 1. EXPLICIT MODE
46+
# ----------------------------------------------------------------
47+
# solve(ocp; discretizer=..., modeler=..., solver=...)
48+
49+
disc_exp = CTDirect.Collocation(grid_size=50, scheme=:midpoint)
50+
mod_exp = CTSolvers.ADNLP()
51+
sol_exp = CTSolvers.Ipopt(print_level=0, max_iter=0)
52+
53+
timed_explicit = @timed begin
54+
OptimalControl.solve(pb.ocp;
55+
initial_guess=pb.init,
56+
discretizer=disc_exp,
57+
modeler=mod_exp,
58+
solver=sol_exp,
59+
display=false
60+
)
61+
end
62+
63+
res_exp = timed_explicit.value
64+
succ_exp = OptimalControl.successful(res_exp)
65+
obj_exp = succ_exp ? OptimalControl.objective(res_exp) : 0.0
66+
iter_exp = OptimalControl.iterations(res_exp)
67+
68+
if VERBOSE
69+
print_test_line(
70+
"Explicit", "Beam", "midpoint", "ADNLP", "Ipopt",
71+
succ_exp, timed_explicit.time, obj_exp, pb.obj,
72+
iter_exp, nothing, false
73+
)
74+
end
75+
76+
total_tests += 1
77+
passed_tests += 1 # We count it as passed if it ran without error
78+
79+
Test.@testset "Explicit Mode" begin
80+
# With max_iter=0, success is likely false, so we only check type
81+
Test.@test res_exp isa OptimalControl.AbstractSolution
82+
end
83+
84+
# ----------------------------------------------------------------
85+
# 2. DESCRIPTIVE MODE (Complete)
86+
# ----------------------------------------------------------------
87+
# solve(ocp, :collocation, :adnlp, :ipopt; ...)
88+
89+
timed_desc = @timed begin
90+
OptimalControl.solve(pb.ocp, :collocation, :adnlp, :ipopt;
91+
initial_guess=pb.init,
92+
grid_size=50, # Routed to discretizer
93+
print_level=0, # Routed to solver
94+
max_iter=0, # Routed to solver
95+
display=false
96+
)
97+
end
98+
99+
res_desc = timed_desc.value
100+
succ_desc = OptimalControl.successful(res_desc)
101+
obj_desc = succ_desc ? OptimalControl.objective(res_desc) : 0.0
102+
iter_desc = OptimalControl.iterations(res_desc)
103+
104+
if VERBOSE
105+
print_test_line(
106+
"Descriptive", "Beam", ":collocation", ":adnlp", ":ipopt",
107+
succ_desc, timed_desc.time, obj_desc, pb.obj,
108+
iter_desc, nothing, false
109+
)
110+
end
111+
112+
total_tests += 1
113+
passed_tests += 1
114+
115+
Test.@testset "Descriptive Mode (Complete)" begin
116+
Test.@test res_desc isa OptimalControl.AbstractSolution
117+
end
118+
119+
# ----------------------------------------------------------------
120+
# 3. DESCRIPTIVE MODE (Partial + Defaults)
121+
# ----------------------------------------------------------------
122+
# solve(ocp, :collocation; ...) -> implies :adnlp, :ipopt
123+
124+
timed_part = @timed begin
125+
OptimalControl.solve(pb.ocp, :collocation;
126+
initial_guess=pb.init,
127+
grid_size=50,
128+
print_level=0,
129+
max_iter=0,
130+
display=false
131+
)
132+
end
133+
134+
res_part = timed_part.value
135+
succ_part = OptimalControl.successful(res_part)
136+
obj_part = succ_part ? OptimalControl.objective(res_part) : 0.0
137+
iter_part = OptimalControl.iterations(res_part)
138+
139+
if VERBOSE
140+
print_test_line(
141+
"Partial", "Beam", ":collocation", "(auto)", "(auto)",
142+
succ_part, timed_part.time, obj_part, pb.obj,
143+
iter_part, nothing, false
144+
)
145+
end
146+
147+
total_tests += 1
148+
passed_tests += 1
149+
150+
Test.@testset "Descriptive Mode (Partial)" begin
151+
Test.@test res_part isa OptimalControl.AbstractSolution
152+
end
153+
154+
# Summary
155+
if VERBOSE
156+
print_summary(total_tests, passed_tests, time() - total_start_time)
157+
end
158+
end
159+
end
160+
161+
end # module
162+
163+
# Entry point
164+
test_solve_modes() = TestSolveModes.test_solve_modes()

0 commit comments

Comments
 (0)