Succesful MBH runs, with some improvements
This commit is contained in:
@@ -51,10 +51,9 @@ function mission_guess( flybys::Vector{Body},
|
||||
sc::Sc,
|
||||
start_mass::Float64,
|
||||
launch_window::Tuple{DateTime, DateTime},
|
||||
max_C3_out::Float64,
|
||||
max_C3::Float64,
|
||||
max_v∞_in_mag::Float64,
|
||||
latest_arrival::DateTime,
|
||||
primary::Body=Sun )
|
||||
latest_arrival::DateTime)
|
||||
mission_guess = Bad_Mission("Keep trying to generate a guess")
|
||||
while mission_guess == Bad_Mission("Keep trying to generate a guess")
|
||||
# TODO: Eventually I can calculate n more intelligently
|
||||
@@ -62,8 +61,9 @@ function mission_guess( flybys::Vector{Body},
|
||||
|
||||
# Determine the launch conditions
|
||||
launch_date = rand(launch_window...)
|
||||
launch_v∞_normalized = rand(-1:0.0001:1, 3)
|
||||
launch_v∞ = rand(0:0.0001:√max_C3_out) * launch_v∞_normalized/norm(launch_v∞_normalized)
|
||||
launch_v∞_unit = rand(-1:0.0001:1, 3)
|
||||
launch_v∞_normalized = launch_v∞_unit/norm(launch_v∞_unit)
|
||||
launch_v∞ = √max_C3 * rand() * launch_v∞_normalized
|
||||
|
||||
# Determine the leg lengths
|
||||
num_phases = length(flybys) - 1
|
||||
@@ -126,14 +126,14 @@ function mbh( flybys::Vector{Body},
|
||||
max_C3::Float64,
|
||||
max_v∞::Float64,
|
||||
latest_arrival::DateTime,
|
||||
cost_fn::Function,
|
||||
primary::Body=Sun;
|
||||
cost_fn::Function;
|
||||
search_patience::Int=10_000,
|
||||
drill_patience::Int=50,
|
||||
verbose::Bool=false)
|
||||
verbose::Bool=false,
|
||||
test::Bool=false )
|
||||
|
||||
# Convenience Functions
|
||||
random_guess() = mission_guess(flybys,sc,start_mass,launch_window,max_C3,max_v∞,latest_arrival,primary)
|
||||
random_guess() = mission_guess(flybys,sc,start_mass,launch_window,max_C3,max_v∞,latest_arrival)
|
||||
solve(g::Mission_Guess) = solve_mission(g, launch_window, latest_arrival)
|
||||
cost(m::Mission) = cost_fn(m, max_C3, max_v∞)
|
||||
cost(_::Nothing) = Inf
|
||||
@@ -143,13 +143,16 @@ function mbh( flybys::Vector{Body},
|
||||
drill_count = 0
|
||||
archive = Vector{Mission}()
|
||||
function log()
|
||||
sct = search_count
|
||||
dct = drill_count
|
||||
lar = length(archive)
|
||||
flyby_abbreviation = join([ f.name[1] for f in flybys ])
|
||||
print("\r ")
|
||||
print("\rsearch: $(search_count) drill: $(drill_count) archive: $(length(archive))\t")
|
||||
print("\rMBH\t$(flyby_abbreviation)\tsearch: $(sct) drill: $(dct) archive: $(lar)\t")
|
||||
end
|
||||
|
||||
# The main loop
|
||||
x_current = nothing
|
||||
if verbose println("Starting Monotonic Basin Hopper") end
|
||||
while search_count < search_patience
|
||||
|
||||
# Intialize an x_star, if it doesn't converge, hop on to the next basin
|
||||
@@ -188,6 +191,12 @@ function mbh( flybys::Vector{Body},
|
||||
|
||||
x_current in archive || push!(archive, x_current)
|
||||
|
||||
# If in test mode, we don't need to actually optimize. Just grab the first valid basin-best
|
||||
if test
|
||||
println()
|
||||
return x_current, [ x_current ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if verbose println() end
|
||||
|
||||
@@ -2,23 +2,27 @@ using SNOW
|
||||
|
||||
export solve_mission
|
||||
|
||||
struct Result
|
||||
converged::Bool
|
||||
info::Symbol
|
||||
sol::Mission_Guess
|
||||
end
|
||||
const pos_scale = ones(3)
|
||||
# const vel_scale = 100. * ones(3)
|
||||
const vel_scale = ones(3)
|
||||
# const v∞_scale = norm(vel_scale)
|
||||
const v∞_scale = 1.
|
||||
const state_scale = [pos_scale; vel_scale ]
|
||||
|
||||
function constraint_bounds(guess::Mission_Guess)
|
||||
low_constraint = Vector{Float64}()
|
||||
high_constraint = Vector{Float64}()
|
||||
|
||||
for phase in guess.phases
|
||||
state_constraint = [100., 100., 100., 0.005, 0.005, 0.005] .* state_scale
|
||||
push!(low_constraint, (-1 * state_constraint)... )
|
||||
push!(high_constraint, state_constraint... )
|
||||
if phase != guess.phases[end]
|
||||
push!(low_constraint, -100., -100., -100., -0.005, -0.005, -0.005, -30., 100.)
|
||||
push!(high_constraint, 100., 100., 100., 0.005, 0.005, 0.005, 30., 100_000.)
|
||||
push!(low_constraint, -0.005*v∞_scale, 100.)
|
||||
push!(high_constraint, 0.005*v∞_scale, 1e7)
|
||||
else
|
||||
push!(low_constraint, -100., -100., -100., 0.)
|
||||
push!(high_constraint, 100., 100., 100., guess.start_mass - guess.sc.dry_mass)
|
||||
push!(low_constraint, 0.)
|
||||
push!(high_constraint, guess.start_mass - guess.sc.dry_mass)
|
||||
end
|
||||
end
|
||||
return low_constraint, high_constraint
|
||||
@@ -33,7 +37,7 @@ guess otherwise
|
||||
function solve_mission( guess::Mission_Guess,
|
||||
launch_window::Tuple{DateTime,DateTime},
|
||||
latest_arrival::DateTime;
|
||||
tol=1e-10,
|
||||
tol=1e-12,
|
||||
verbose::Bool=false,
|
||||
print_level=0 )
|
||||
|
||||
@@ -45,64 +49,71 @@ function solve_mission( guess::Mission_Guess,
|
||||
# And our NLP
|
||||
function optimizer!(g,x)
|
||||
# Establish initial conditions
|
||||
mass = guess.start_mass
|
||||
v∞_out = x[2:4]
|
||||
current_planet = Earth
|
||||
launch_date = Dates.unix2datetime(x[1])
|
||||
time = utc2et(Dates.format(launch_date,"yyyy-mm-ddTHH:MM:SS"))
|
||||
start = state(current_planet, time, v∞_out, mass)
|
||||
start = state(current_planet, time, v∞_out, guess.start_mass)
|
||||
|
||||
# Now, for each phase we must require:
|
||||
# - That the ending state matches (unless final leg)
|
||||
# - That the ending state matches (all legs)
|
||||
# - That the v∞_out == v∞_in (unless final leg)
|
||||
# - That the minimum height is acceptable (unless final leg)
|
||||
# - That the ending position matches (if final leg)
|
||||
# - That the ending mass is acceptable (if final leg)
|
||||
i = 0
|
||||
try
|
||||
|
||||
for flyby in flybys
|
||||
# Get the values from the vector
|
||||
phase_params = x[ 5 + (3n+7) * i : 5 + (3n+7) * (i+1) - 1 ]
|
||||
v∞_in = phase_params[1:3]
|
||||
v∞_out = phase_params[4:6]
|
||||
tof = phase_params[7]
|
||||
thrusts = reshape(phase_params[8:end], (n,3))
|
||||
|
||||
# Propagate
|
||||
final = prop(thrusts, start, guess.sc, tof)[2]
|
||||
current_planet = flyby
|
||||
time += tof
|
||||
goal = state(current_planet, time, v∞_in)
|
||||
final = prop(reshape(thrusts, (n,3)), start, guess.sc, tof)[2]
|
||||
goal = state(current_planet, time, v∞_in)[1:6]
|
||||
start = state(current_planet, time, v∞_out, final[7])
|
||||
|
||||
# Do Checks
|
||||
g[1+8i:6+8i] .= (final[1:6] .- goal[1:6]) .* state_scale
|
||||
if flyby != flybys[end]
|
||||
g[1+8i:6+8i] .= (final[1:6] .- goal[1:6]) .* [1., 1., 1., 10_000., 10_000., 10_000.]
|
||||
g[7+8i] = (norm(v∞_out) - norm(v∞_in)) * 10_000.
|
||||
g[7+8i] = (norm(v∞_out) - norm(v∞_in)) * v∞_scale
|
||||
δ = acos( ( v∞_in ⋅ v∞_out ) / ( norm(v∞_in) * norm(v∞_out) ) )
|
||||
g[8+8i] = (current_planet.μ/(v∞_in ⋅ v∞_in)) * ( 1/sin(δ/2) - 1 ) - current_planet.r
|
||||
else
|
||||
g[8*(length(flybys)-1)+1:8*(length(flybys)-1)+3] .= final[1:3] .- goal[1:3]
|
||||
g[8*(length(flybys)-1)+4] = final[7] - guess.sc.dry_mass
|
||||
g[8*(length(flybys)-1)+7] = final[7] - guess.sc.dry_mass
|
||||
end
|
||||
start = state(current_planet, time, v∞_out, final[7])
|
||||
mass = final[7]
|
||||
i += 1
|
||||
end
|
||||
return 1.0
|
||||
|
||||
catch e
|
||||
|
||||
if isa(e,LaGuerreConway_Error)
|
||||
g[1:8*(length(flybys)-1)+4] .= 1e10
|
||||
g[1:8*(length(flybys)-1)+7] .= 1e10
|
||||
return 1e10
|
||||
else
|
||||
rethrow()
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
max_time = Dates.datetime2unix(latest_arrival) - Dates.datetime2unix(launch_window[1])
|
||||
lower_x = lowest_mission_vector(launch_window, length(guess.phases), n)
|
||||
upper_x = highest_mission_vector(launch_window, max_time, length(guess.phases), n)
|
||||
num_constraints = 8*(length(guess.phases)-1) + 4
|
||||
num_constraints = 8*(length(guess.phases)-1) + 7
|
||||
g_low, g_high = constraint_bounds(guess)
|
||||
ipopt_options = Dict("constr_viol_tol" => tol,
|
||||
"acceptable_constr_viol_tol" => 100tol,
|
||||
"bound_relax_factor" => 0.,
|
||||
"max_iter" => 100_000,
|
||||
"max_cpu_time" => 60.,
|
||||
"max_cpu_time" => 5. * length(guess.phases),
|
||||
"print_level" => print_level)
|
||||
options = Options(solver=IPOPT(ipopt_options), derivatives=ForwardFD())
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ function prop_one(ΔV_unit::Vector{<:Real},
|
||||
ΔV = max_ΔV(craft.duty_cycle, craft.num_thrusters, craft.max_thrust, time, 0., state[7]) * ΔV_unit
|
||||
halfway = laguerre_conway(state, time/2, primary) + [zeros(3); ΔV]
|
||||
final = laguerre_conway(halfway, time/2, primary)
|
||||
return [final; state[7] - craft.mass_flow_rate*norm(ΔV_unit)*time]
|
||||
return [final; state[7] - mfr(craft)*norm(ΔV_unit)*time]
|
||||
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user