Succesful MBH runs, with some improvements

This commit is contained in:
Connor
2021-10-12 21:49:46 -06:00
parent c7913d2944
commit bb78578d9a
19 changed files with 426 additions and 146 deletions

View File

@@ -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

View File

@@ -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())

View File

@@ -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