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