diff --git a/Project.toml b/Project.toml index bcbd01c..ecfdb3b 100644 --- a/Project.toml +++ b/Project.toml @@ -1,33 +1,49 @@ name = "JuliaCon2026Components" uuid = "cb0cf210-d080-4a98-89fc-0e4ae9a4086e" -authors = [" <>"] version = "0.1.0" +authors = [" <>"] [deps] -Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" +BlockComponents = "1ef5d832-be8e-447f-9f2c-8b5d17d15fd3" +DyadData = "cab12561-e36c-4498-ae70-c9a5e79fef2a" DyadInterface = "99806f68-afab-45ca-9d8c-ceff6bc61f54" +ElectricalComponents = "3fc4c519-469d-4ff5-98c9-d4d06b1514a2" +HydraulicComponents = "b6ec4bdb-baef-4449-8ab3-f7a9cc7f1342" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" +Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a" ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" Moshi = "2e0e35c7-a2e4-4343-998d-7ef72827ed2d" +MultibodyComponents = "01883e52-22cd-4538-b14d-b44f958a131d" OrdinaryDiffEqDefault = "50262376-6c5a-4cf5-baba-aaf4f84d72d7" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" +RotationalComponents = "824fa3ed-d7dc-4365-8bdf-ac77a1ac2011" RuntimeGeneratedFunctions = "7e49a35a-f44a-4d26-94aa-eba1b4ca6b47" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +ThermalComponents = "084a29d9-4f48-4925-95b4-b7d4c79725f4" +TranslationalComponents = "42acc370-819b-4877-bdd6-eb3294461f5d" [compat] -Markdown = "1" +BlockComponents = "4.5.1" +DyadData = "2.0.1" +ElectricalComponents = "2.2.1" +HydraulicComponents = "2.0.3" JSON = "0.21, 1" +Markdown = "1" +MultibodyComponents = "0.2.3" +RotationalComponents = "2.5.4" TOML = "1" +ThermalComponents = "2.0.5" +TranslationalComponents = "2.5.0" + +[dyad] +kernel = "3.3.0" [extras] -DyadEcosystemDependencies = "7bc808db-8006-421e-b546-062440d520b7" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" +DyadEcosystemDependencies = "7bc808db-8006-421e-b546-062440d520b7" Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["DyadEcosystemDependencies","CSV","DataFrames","Plots","Test"] - -[dyad] -kernel = "3.3.0" \ No newline at end of file +test = ["DyadEcosystemDependencies", "CSV", "DataFrames", "Plots", "Test"] diff --git a/dyad/rocket.dyad b/dyad/rocket.dyad new file mode 100644 index 0000000..1029f0e --- /dev/null +++ b/dyad/rocket.dyad @@ -0,0 +1,183 @@ +""" +Free-flying point body with time-varying mass in an inverse-square (point) +gravity field. Translational dynamics only: orientation is held fixed at the +identity so no rotational states are introduced. + +The instantaneous total mass is supplied through the `m_in` signal, so the +staging / propellant logic can live in the enclosing model. External forces +(thrust, drag) enter through `frame_a`; gravity is computed internally from the +absolute position. + +Newton's law in the frame (with R = I, r_cm = 0) mirrors the standard +`MultibodyComponents.Body`: `frame_a.f = m * (a_0 - g_0)`. +""" +component VariableMassBody + "Gravitational parameter of the central body [m^3/s^2]" + parameter mu::Real(units="m3/s2") = 3.986004418e14 + frame_a = Frame3D() + "Instantaneous total mass" + m_in = RealInput() + "Absolute position resolved in the world frame" + variable r_0::Position[3] + "Absolute velocity resolved in the world frame" + variable v_0::Velocity[3] + "Absolute acceleration resolved in the world frame" + variable a_0::Acceleration[3] + "Gravitational acceleration resolved in the world frame" + variable g_0::Acceleration[3] + "Distance from the central body centre" + variable rmag::Length +relations + r_0 = frame_a.r_0 + v_0 = der(r_0) + a_0 = der(v_0) + # Fixed orientation: identity rotation, no torque + frame_a.R = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + frame_a.tau = [0, 0, 0] + # Inverse-square gravity pointing toward the origin + rmag = sqrt(r_0[1]^2 + r_0[2]^2 + r_0[3]^2) + g_0 = (-mu / rmag^3) * r_0 + # Newton's second law with time-varying mass + frame_a.f = m_in * (a_0 - g_0) +end + +""" +Two-stage launch vehicle flying a gravity-turn ascent to escape velocity. + +The rocket is a `VariableMassBody` in a point-gravity field. Thrust and +aerodynamic drag are applied through `MultibodyComponents.WorldForce` elements +attached to the body frame. Propellant burn, staging (jettison of the spent +launch vehicle when stage-1 propellant is depleted), the open-loop pitch +program, and the exponential-atmosphere drag law are all expressed here. + +Coordinates: launch from `[0, R_body, 0]`, downrange toward `+x`, motion in the +x-y plane. Escape is checked via the specific orbital energy +`spec_energy = v^2/2 - mu/r >= 0`. +""" +component TwoStageRocket + # ---- Environment ---- + "Gravitational parameter [m^3/s^2]" + parameter mu::Real = 3.986004418e14 + "Central body radius [m]" + parameter R_body::Real = 6.371e6 + "Sea-level atmospheric density [kg/m^3]" + parameter rho0::Real = 1.225 + "Atmospheric scale height [m]" + parameter Hscale::Real = 8500.0 + # ---- Stage 1 (launch vehicle) ---- + "Stage-1 structural (dry) mass [kg]" + parameter m1_dry::Real = 18000.0 + "Stage-1 propellant mass [kg]" + parameter m1_prop::Real = 320000.0 + "Stage-1 exhaust velocity [m/s]" + parameter ve1::Real = 3100.0 + "Stage-1 propellant mass-flow rate [kg/s]" + parameter mdot1::Real = 2200.0 + "Full-stack reference (frontal) area [m^2]" + parameter A_stack::Real = 11.0 + # ---- Stage 2 (orbiter) ---- + "Stage-2 structural (dry) mass [kg]" + parameter m2_dry::Real = 3500.0 + "Stage-2 propellant mass [kg]" + parameter m2_prop::Real = 80000.0 + "Stage-2 exhaust velocity [m/s]" + parameter ve2::Real = 4400.0 + "Stage-2 propellant mass-flow rate [kg/s]" + parameter mdot2::Real = 260.0 + "Orbiter reference (frontal) area [m^2]" + parameter A_orbiter::Real = 5.0 + # ---- Payload & aerodynamics ---- + "Payload mass carried to the end [kg]" + parameter payload::Real = 1500.0 + "Drag coefficient" + parameter Cd::Real = 0.4 + # ---- Pitch program (open-loop gravity turn) ---- + "Duration of the initial vertical rise [s]" + parameter t_vert::Real = 12.0 + "Time at which the pitch-over ramp ends [s]" + parameter t_pitch_end::Real = 140.0 + "Held pitch angle from local vertical [rad]" + parameter phi_max::Real = 1.05 + # ---- Multibody components ---- + world = MultibodyComponents.World() + body = VariableMassBody(mu = mu, r_0 = initial [0, R_body, 0], v_0 = initial [0, 0, 0]) + thrust = MultibodyComponents.WorldForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.World()) + drag = MultibodyComponents.WorldForce(resolve_in_frame = MultibodyComponents.ResolveInFrame.World()) + # ---- Propellant states ---- + variable mp1::Real + variable mp2::Real + # ---- Diagnostics / intermediate quantities ---- + variable m::Real + variable Fthrust::Real + variable phi::Real + variable rmag::Real + variable vmag::Real + variable altitude::Real + variable rho::Real + variable q::Real + variable A::Real + variable stage::Real + variable radial_hat::Real[3] + variable downrange_hat::Real[3] + variable thrust_dir::Real[3] + variable v_esc::Real + variable spec_energy::Real +relations + initial mp1 = m1_prop + initial mp2 = m2_prop + # Propellant burn; staging by depletion of stage-1 propellant + der(mp1) = ifelse(mp1 > 0.0, -mdot1, 0.0) + der(mp2) = ifelse(mp1 > 0.0, 0.0, ifelse(mp2 > 0.0, -mdot2, 0.0)) + # Thrust magnitude: stage-1, then stage-2, then coast + Fthrust = ifelse(mp1 > 0.0, mdot1 * ve1, ifelse(mp2 > 0.0, mdot2 * ve2, 0.0)) + # Total mass; jettison the spent launch vehicle at staging + m = ifelse(mp1 > 0.0, m1_dry + mp1 + m2_dry + mp2 + payload, m2_dry + mp2 + payload) + # Reference area switches from full stack to orbiter at staging + A = ifelse(mp1 > 0.0, A_stack, A_orbiter) + stage = ifelse(mp1 > 0.0, 1.0, ifelse(mp2 > 0.0, 2.0, 0.0)) + # Kinematics from the body + rmag = sqrt(body.r_0[1]^2 + body.r_0[2]^2 + body.r_0[3]^2) + vmag = sqrt(body.v_0[1]^2 + body.v_0[2]^2 + body.v_0[3]^2) + altitude = rmag - R_body + # Guidance: pitch program relative to the local vertical + radial_hat = body.r_0 / rmag + downrange_hat = [body.r_0[2], -body.r_0[1], 0] / rmag + phi = ifelse(time < t_vert, 0.0, + ifelse(time < t_pitch_end, phi_max * (time - t_vert) / (t_pitch_end - t_vert), phi_max)) + thrust_dir = cos(phi) * radial_hat + sin(phi) * downrange_hat + # Atmosphere and dynamic pressure + rho = rho0 * exp(-altitude / Hscale) + q = 0.5 * rho * vmag^2 + # Drive the multibody force elements and the body mass + body.m_in = m + thrust.force_x = Fthrust * thrust_dir[1] + thrust.force_y = Fthrust * thrust_dir[2] + thrust.force_z = Fthrust * thrust_dir[3] + drag.force_x = -Cd * 0.5 * rho * A * vmag * body.v_0[1] + drag.force_y = -Cd * 0.5 * rho * A * vmag * body.v_0[2] + drag.force_z = -Cd * 0.5 * rho * A * vmag * body.v_0[3] + connect(thrust.frame_b, body.frame_a) + connect(drag.frame_b, body.frame_a) + # Escape diagnostics + v_esc = sqrt(2 * mu / rmag) + spec_energy = 0.5 * vmag^2 - mu / rmag +end + +analysis LaunchToEscape + extends TransientAnalysis(stop=2000, abstol=1e-6, reltol=1e-6) + model = TwoStageRocket() +end + +"Orbit sanity check: constant-mass body on a circular orbit must keep constant radius." +test component TestOrbit + world = MultibodyComponents.World() + mass = BlockComponents.Sources.Constant(k=1.0) + body = VariableMassBody(r_0 = initial [7.0e6, 0, 0], v_0 = initial [0, 7546.05, 0]) +relations + connect(mass.y, body.m_in) +end + +analysis TestOrbitTransient + extends TransientAnalysis(stop=6000, abstol=1e-8, reltol=1e-8) + model = TestOrbit() +end diff --git a/generated/LaunchToEscape_definition.jl b/generated/LaunchToEscape_definition.jl new file mode 100644 index 0000000..1b57a22 --- /dev/null +++ b/generated/LaunchToEscape_definition.jl @@ -0,0 +1,52 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + +using DyadInterface +using DyadInterface: ODEAlg, DEVerbosity, OptimizationLevel +using ModelingToolkit: SymbolicT, toggle_namespacing +using DyadInterface: AbstractTransientAnalysisSpec, TransientAnalysisSpec +@kwdef mutable struct LaunchToEscapeSpec <: AbstractTransientAnalysisSpec + name::Symbol = :LaunchToEscape + var"alg"::ODEAlg.Type = ODEAlg.Auto() + var"start"::Float64 = 0 + var"stop"::Float64 = 2000 + var"abstol"::Float64 = 0.000001 + var"reltol"::Float64 = 0.000001 + var"saveat"::Float64 = 0 + var"dtmax"::Float64 = 0 + var"tstops"::Array{Float64, 1} = [] + var"automatic_discontinuity_detection"::Bool = false + var"optimize"::OptimizationLevel.Type = OptimizationLevel.Aggressive() + var"progress"::Bool = true + var"respecialize"::Bool = false + var"verbose"::DEVerbosity.Type = DEVerbosity.Standard() + var"log_file"::String = "" + # Two-stage launch vehicle flying a gravity-turn ascent to escape velocity. + # + # The rocket is a `VariableMassBody` in a point-gravity field. Thrust and + # aerodynamic drag are applied through `MultibodyComponents.WorldForce` elements + # attached to the body frame. Propellant burn, staging (jettison of the spent + # launch vehicle when stage-1 propellant is depleted), the open-loop pitch + # program, and the exponential-atmosphere drag law are all expressed here. + # + # Coordinates: launch from `[0, R_body, 0]`, downrange toward `+x`, motion in the + # x-y plane. Escape is checked via the specific orbital energy + # `spec_energy = v^2/2 - mu/r >= 0`. + var"model"::Union{Nothing, System} = JuliaCon2026Components.TwoStageRocket(; name=:TwoStageRocket) +end + +function DyadInterface.run_analysis(spec::LaunchToEscapeSpec) + overrides = Dict{SymbolicT, SymbolicT}() + no_namespace_model = toggle_namespacing(spec.model, false) + + base_spec = TransientAnalysisSpec(; + name=:TransientAnalysis, overrides, alg=spec.alg, start=spec.start, stop=spec.stop, abstol=spec.abstol, reltol=spec.reltol, saveat=spec.saveat, dtmax=spec.dtmax, tstops=spec.tstops, automatic_discontinuity_detection=spec.automatic_discontinuity_detection, optimize=spec.optimize, progress=spec.progress, respecialize=spec.respecialize, verbose=spec.verbose, log_file=spec.log_file, model=spec.model + ) + run_analysis(base_spec) +end + +LaunchToEscape(;kwargs...) = run_analysis(LaunchToEscapeSpec(;kwargs...)) +export LaunchToEscape, LaunchToEscapeSpec diff --git a/generated/TestOrbitTransient_definition.jl b/generated/TestOrbitTransient_definition.jl new file mode 100644 index 0000000..7001d29 --- /dev/null +++ b/generated/TestOrbitTransient_definition.jl @@ -0,0 +1,42 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + +using DyadInterface +using DyadInterface: ODEAlg, DEVerbosity, OptimizationLevel +using ModelingToolkit: SymbolicT, toggle_namespacing +using DyadInterface: AbstractTransientAnalysisSpec, TransientAnalysisSpec +@kwdef mutable struct TestOrbitTransientSpec <: AbstractTransientAnalysisSpec + name::Symbol = :TestOrbitTransient + var"alg"::ODEAlg.Type = ODEAlg.Auto() + var"start"::Float64 = 0 + var"stop"::Float64 = 6000 + var"abstol"::Float64 = 1e-8 + var"reltol"::Float64 = 1e-8 + var"saveat"::Float64 = 0 + var"dtmax"::Float64 = 0 + var"tstops"::Array{Float64, 1} = [] + var"automatic_discontinuity_detection"::Bool = false + var"optimize"::OptimizationLevel.Type = OptimizationLevel.Aggressive() + var"progress"::Bool = true + var"respecialize"::Bool = false + var"verbose"::DEVerbosity.Type = DEVerbosity.Standard() + var"log_file"::String = "" + # Orbit sanity check: constant-mass body on a circular orbit must keep constant radius. + var"model"::Union{Nothing, System} = JuliaCon2026Components.TestOrbit(; name=:TestOrbit) +end + +function DyadInterface.run_analysis(spec::TestOrbitTransientSpec) + overrides = Dict{SymbolicT, SymbolicT}() + no_namespace_model = toggle_namespacing(spec.model, false) + + base_spec = TransientAnalysisSpec(; + name=:TransientAnalysis, overrides, alg=spec.alg, start=spec.start, stop=spec.stop, abstol=spec.abstol, reltol=spec.reltol, saveat=spec.saveat, dtmax=spec.dtmax, tstops=spec.tstops, automatic_discontinuity_detection=spec.automatic_discontinuity_detection, optimize=spec.optimize, progress=spec.progress, respecialize=spec.respecialize, verbose=spec.verbose, log_file=spec.log_file, model=spec.model + ) + run_analysis(base_spec) +end + +TestOrbitTransient(;kwargs...) = run_analysis(TestOrbitTransientSpec(;kwargs...)) +export TestOrbitTransient, TestOrbitTransientSpec diff --git a/generated/TestOrbit_definition.jl b/generated/TestOrbit_definition.jl new file mode 100644 index 0000000..25030d8 --- /dev/null +++ b/generated/TestOrbit_definition.jl @@ -0,0 +1,84 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + +import Moshi as __Ext__Moshi + +@doc Markdown.doc""" + TestOrbit(; name) + +Orbit sanity check: constant-mass body on a circular orbit must keep constant radius. +""" +@component function TestOrbit(; name = nothing, kwargs...) + isnothing(name) && throw(ArgumentError(""" + The `name` keyword must be provided. Please consider using the `@named` macro, + like so: + + @named model = TestOrbit() + """)) + + __overrides = __build_overrides(kwargs) + __params = Symbolics.SymbolicT[] + __vars = Symbolics.SymbolicT[] + __systems = System[] + __guesses = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + __initial_conditions = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + __initialization_eqs = Equation[] + __eqs = Equation[] + __bindings = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + + ### Structural Parameters (functions) + + ### Structural Parameters (Final) + + ### Path Parameters (functions) + + ### Path Parameters (non-final) + + ### Final Parameters (declarations) + + ### Deferred assignment (default values that depend on final parameters) + + ### Symbolic Parameters + + ### Final Parameters (assignments) + + ### Final Path Parameters + + ### Variables (declarations) + + ### Variables (assignments) + + ### Constants + __constants = Any[] + + ### Components + # Subcomponent world of type MultibodyComponents.World + world_overrides = __pop_subcomponent_overrides!(__overrides, "world") + push!(__systems, @named world = MultibodyComponents.World(; world_overrides...)) + # Subcomponent mass of type BlockComponents.Sources.Constant + mass_overrides = __pop_subcomponent_overrides!(__overrides, "mass") + push!(__systems, @named mass = BlockComponents.Sources.Constant(; k=Float64(1.0), mass_overrides...)) + # Subcomponent body of type JuliaCon2026Components.VariableMassBody + body_overrides = __pop_subcomponent_overrides!(__overrides, "body") + push!(__systems, @named body = JuliaCon2026Components.VariableMassBody(; r_0__initial=[7000000.0, 0, 0], v_0__initial=[0, 7546.05, 0], body_overrides...)) + + ### Check there are no unmatched overrides + isempty(__overrides) || throw(ArgumentError("overrides: [$(join(keys(__overrides), ", "))] don't match names found in model. These names may exist in the model but could have been conditionally excluded.")) + + ### Guesses + + ### Initialization Equations + + ### Assertions + __assertions = [] + + ### Equations + push!(__eqs, connect(mass.y, body.m_in)) + + # Return completely constructed System + return System(__eqs, t, __vars, __params; systems=__systems, initial_conditions=__initial_conditions, guesses=__guesses, name, initialization_eqs=__initialization_eqs, bindings=__bindings, assertions=__assertions) +end +export TestOrbit diff --git a/generated/TestOrbit_experiment.jl b/generated/TestOrbit_experiment.jl new file mode 100644 index 0000000..4bb4837 --- /dev/null +++ b/generated/TestOrbit_experiment.jl @@ -0,0 +1,7 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + + diff --git a/generated/TestOrbit_test.jl b/generated/TestOrbit_test.jl new file mode 100644 index 0000000..4bb4837 --- /dev/null +++ b/generated/TestOrbit_test.jl @@ -0,0 +1,7 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + + diff --git a/generated/TwoStageRocket_definition.jl b/generated/TwoStageRocket_definition.jl new file mode 100644 index 0000000..74f2c1f --- /dev/null +++ b/generated/TwoStageRocket_definition.jl @@ -0,0 +1,312 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + +import Moshi as __Ext__Moshi + +@doc Markdown.doc""" + TwoStageRocket(; name, mu, R_body, rho0, Hscale, m1_dry, m1_prop, ve1, mdot1, A_stack, m2_dry, m2_prop, ve2, mdot2, A_orbiter, payload, Cd, t_vert, t_pitch_end, phi_max) + +Two-stage launch vehicle flying a gravity-turn ascent to escape velocity. + +The rocket is a `VariableMassBody` in a point-gravity field. Thrust and +aerodynamic drag are applied through `MultibodyComponents.WorldForce` elements +attached to the body frame. Propellant burn, staging (jettison of the spent +launch vehicle when stage-1 propellant is depleted), the open-loop pitch +program, and the exponential-atmosphere drag law are all expressed here. + +Coordinates: launch from `[0, R_body, 0]`, downrange toward `+x`, motion in the +x-y plane. Escape is checked via the specific orbital energy +`spec_energy = v^2/2 - mu/r >= 0`. + +## Parameters: + +| Name | Description | Units | Default value | +| ------------ | ----------------------------------- | ------ | --------------- | +| `mu` | Gravitational parameter [m^3/s^2] | -- | 3.986004418e14 | +| `R_body` | Central body radius [m] | -- | 6.371e6 | +| `rho0` | Sea-level atmospheric density [kg/m^3] | -- | 1.225 | +| `Hscale` | Atmospheric scale height [m] | -- | 8500.0 | +| `m1_dry` | Stage-1 structural (dry) mass [kg] | -- | 18000.0 | +| `m1_prop` | Stage-1 propellant mass [kg] | -- | 320000.0 | +| `ve1` | Stage-1 exhaust velocity [m/s] | -- | 3100.0 | +| `mdot1` | Stage-1 propellant mass-flow rate [kg/s] | -- | 2200.0 | +| `A_stack` | Full-stack reference (frontal) area [m^2] | -- | 11.0 | +| `m2_dry` | Stage-2 structural (dry) mass [kg] | -- | 3500.0 | +| `m2_prop` | Stage-2 propellant mass [kg] | -- | 80000.0 | +| `ve2` | Stage-2 exhaust velocity [m/s] | -- | 4400.0 | +| `mdot2` | Stage-2 propellant mass-flow rate [kg/s] | -- | 260.0 | +| `A_orbiter` | Orbiter reference (frontal) area [m^2] | -- | 5.0 | +| `payload` | Payload mass carried to the end [kg] | -- | 1500.0 | +| `Cd` | Drag coefficient | -- | 0.4 | +| `t_vert` | Duration of the initial vertical rise [s] | -- | 12.0 | +| `t_pitch_end` | Time at which the pitch-over ramp ends [s] | -- | 140.0 | +| `phi_max` | Held pitch angle from local vertical [rad] | -- | 1.05 | + +## Variables + +| Name | Description | Units | +| ------------ | ----------------------------------- | ------ | +| `mp1` | | -- | +| `mp2` | | -- | +| `m` | | -- | +| `Fthrust` | | -- | +| `phi` | | -- | +| `rmag` | | -- | +| `vmag` | | -- | +| `altitude` | | -- | +| `rho` | | -- | +| `q` | | -- | +| `A` | | -- | +| `stage` | | -- | +| `radial_hat` | | -- | +| `downrange_hat` | | -- | +| `thrust_dir` | | -- | +| `v_esc` | | -- | +| `spec_energy` | | -- | +""" +@component function TwoStageRocket(; name = nothing, mu=Float64(398600441800000.0), R_body=Float64(6371000.0), rho0=1.225, Hscale=Float64(8500.0), m1_dry=Float64(18000.0), m1_prop=Float64(320000.0), ve1=Float64(3100.0), mdot1=Float64(2200.0), A_stack=Float64(11.0), m2_dry=Float64(3500.0), m2_prop=Float64(80000.0), ve2=Float64(4400.0), mdot2=Float64(260.0), A_orbiter=Float64(5.0), payload=Float64(1500.0), Cd=0.4, t_vert=Float64(12.0), t_pitch_end=Float64(140.0), phi_max=1.05, kwargs...) + isnothing(name) && throw(ArgumentError(""" + The `name` keyword must be provided. Please consider using the `@named` macro, + like so: + + @named model = TwoStageRocket() + """)) + + __overrides = __build_overrides(kwargs) + __params = Symbolics.SymbolicT[] + __vars = Symbolics.SymbolicT[] + __systems = System[] + __guesses = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + __initial_conditions = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + __initialization_eqs = Equation[] + __eqs = Equation[] + __bindings = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + + ### Structural Parameters (functions) + + ### Structural Parameters (Final) + + ### Path Parameters (functions) + + ### Path Parameters (non-final) + + ### Final Parameters (declarations) + + ### Deferred assignment (default values that depend on final parameters) + + ### Symbolic Parameters + __local__mu = mu + append!(__params, @parameters (mu::Real), [description = "Gravitational parameter [m^3/s^2]"]) + __initial_conditions[mu] = __local__mu + __local__R_body = R_body + append!(__params, @parameters (R_body::Real), [description = "Central body radius [m]"]) + __initial_conditions[R_body] = __local__R_body + __local__rho0 = rho0 + append!(__params, @parameters (rho0::Real), [description = "Sea-level atmospheric density [kg/m^3]"]) + __initial_conditions[rho0] = __local__rho0 + __local__Hscale = Hscale + append!(__params, @parameters (Hscale::Real), [description = "Atmospheric scale height [m]"]) + __initial_conditions[Hscale] = __local__Hscale + __local__m1_dry = m1_dry + append!(__params, @parameters (m1_dry::Real), [description = "Stage-1 structural (dry) mass [kg]"]) + __initial_conditions[m1_dry] = __local__m1_dry + __local__m1_prop = m1_prop + append!(__params, @parameters (m1_prop::Real), [description = "Stage-1 propellant mass [kg]"]) + __initial_conditions[m1_prop] = __local__m1_prop + __local__ve1 = ve1 + append!(__params, @parameters (ve1::Real), [description = "Stage-1 exhaust velocity [m/s]"]) + __initial_conditions[ve1] = __local__ve1 + __local__mdot1 = mdot1 + append!(__params, @parameters (mdot1::Real), [description = "Stage-1 propellant mass-flow rate [kg/s]"]) + __initial_conditions[mdot1] = __local__mdot1 + __local__A_stack = A_stack + append!(__params, @parameters (A_stack::Real), [description = "Full-stack reference (frontal) area [m^2]"]) + __initial_conditions[A_stack] = __local__A_stack + __local__m2_dry = m2_dry + append!(__params, @parameters (m2_dry::Real), [description = "Stage-2 structural (dry) mass [kg]"]) + __initial_conditions[m2_dry] = __local__m2_dry + __local__m2_prop = m2_prop + append!(__params, @parameters (m2_prop::Real), [description = "Stage-2 propellant mass [kg]"]) + __initial_conditions[m2_prop] = __local__m2_prop + __local__ve2 = ve2 + append!(__params, @parameters (ve2::Real), [description = "Stage-2 exhaust velocity [m/s]"]) + __initial_conditions[ve2] = __local__ve2 + __local__mdot2 = mdot2 + append!(__params, @parameters (mdot2::Real), [description = "Stage-2 propellant mass-flow rate [kg/s]"]) + __initial_conditions[mdot2] = __local__mdot2 + __local__A_orbiter = A_orbiter + append!(__params, @parameters (A_orbiter::Real), [description = "Orbiter reference (frontal) area [m^2]"]) + __initial_conditions[A_orbiter] = __local__A_orbiter + __local__payload = payload + append!(__params, @parameters (payload::Real), [description = "Payload mass carried to the end [kg]"]) + __initial_conditions[payload] = __local__payload + __local__Cd = Cd + append!(__params, @parameters (Cd::Real), [description = "Drag coefficient"]) + __initial_conditions[Cd] = __local__Cd + __local__t_vert = t_vert + append!(__params, @parameters (t_vert::Real), [description = "Duration of the initial vertical rise [s]"]) + __initial_conditions[t_vert] = __local__t_vert + __local__t_pitch_end = t_pitch_end + append!(__params, @parameters (t_pitch_end::Real), [description = "Time at which the pitch-over ramp ends [s]"]) + __initial_conditions[t_pitch_end] = __local__t_pitch_end + __local__phi_max = phi_max + append!(__params, @parameters (phi_max::Real), [description = "Held pitch angle from local vertical [rad]"]) + __initial_conditions[phi_max] = __local__phi_max + + ### Final Parameters (assignments) + + ### Final Path Parameters + + ### Variables (declarations) + append!(__vars, @variables (mp1(t)::Real)) + append!(__vars, @variables (mp2(t)::Real)) + append!(__vars, @variables (m(t)::Real)) + append!(__vars, @variables (Fthrust(t)::Real)) + append!(__vars, @variables (phi(t)::Real)) + append!(__vars, @variables (rmag(t)::Real)) + append!(__vars, @variables (vmag(t)::Real)) + append!(__vars, @variables (altitude(t)::Real)) + append!(__vars, @variables (rho(t)::Real)) + append!(__vars, @variables (q(t)::Real)) + append!(__vars, @variables (A(t)::Real)) + append!(__vars, @variables (stage(t)::Real)) + append!(__vars, @variables (radial_hat(t)[1:3]::Real)) + append!(__vars, @variables (downrange_hat(t)[1:3]::Real)) + append!(__vars, @variables (thrust_dir(t)[1:3]::Real)) + append!(__vars, @variables (v_esc(t)::Real)) + append!(__vars, @variables (spec_energy(t)::Real)) + + ### Variables (assignments) + __ovr_mp1 = pop!(__overrides, "mp1", nothing); isnothing(__ovr_mp1) || push!(__eqs, mp1 ~ __ovr_mp1) + __ovr_mp1__initial = pop!(__overrides, "mp1__initial", nothing); isnothing(__ovr_mp1__initial) || (__initial_conditions[mp1] = __ovr_mp1__initial) + __ovr_mp1__guess = pop!(__overrides, "mp1__guess", nothing) + __ovr_mp2 = pop!(__overrides, "mp2", nothing); isnothing(__ovr_mp2) || push!(__eqs, mp2 ~ __ovr_mp2) + __ovr_mp2__initial = pop!(__overrides, "mp2__initial", nothing); isnothing(__ovr_mp2__initial) || (__initial_conditions[mp2] = __ovr_mp2__initial) + __ovr_mp2__guess = pop!(__overrides, "mp2__guess", nothing) + __ovr_m = pop!(__overrides, "m", nothing); isnothing(__ovr_m) || push!(__eqs, m ~ __ovr_m) + __ovr_m__initial = pop!(__overrides, "m__initial", nothing); isnothing(__ovr_m__initial) || (__initial_conditions[m] = __ovr_m__initial) + __ovr_m__guess = pop!(__overrides, "m__guess", nothing) + __ovr_Fthrust = pop!(__overrides, "Fthrust", nothing); isnothing(__ovr_Fthrust) || push!(__eqs, Fthrust ~ __ovr_Fthrust) + __ovr_Fthrust__initial = pop!(__overrides, "Fthrust__initial", nothing); isnothing(__ovr_Fthrust__initial) || (__initial_conditions[Fthrust] = __ovr_Fthrust__initial) + __ovr_Fthrust__guess = pop!(__overrides, "Fthrust__guess", nothing) + __ovr_phi = pop!(__overrides, "phi", nothing); isnothing(__ovr_phi) || push!(__eqs, phi ~ __ovr_phi) + __ovr_phi__initial = pop!(__overrides, "phi__initial", nothing); isnothing(__ovr_phi__initial) || (__initial_conditions[phi] = __ovr_phi__initial) + __ovr_phi__guess = pop!(__overrides, "phi__guess", nothing) + __ovr_rmag = pop!(__overrides, "rmag", nothing); isnothing(__ovr_rmag) || push!(__eqs, rmag ~ __ovr_rmag) + __ovr_rmag__initial = pop!(__overrides, "rmag__initial", nothing); isnothing(__ovr_rmag__initial) || (__initial_conditions[rmag] = __ovr_rmag__initial) + __ovr_rmag__guess = pop!(__overrides, "rmag__guess", nothing) + __ovr_vmag = pop!(__overrides, "vmag", nothing); isnothing(__ovr_vmag) || push!(__eqs, vmag ~ __ovr_vmag) + __ovr_vmag__initial = pop!(__overrides, "vmag__initial", nothing); isnothing(__ovr_vmag__initial) || (__initial_conditions[vmag] = __ovr_vmag__initial) + __ovr_vmag__guess = pop!(__overrides, "vmag__guess", nothing) + __ovr_altitude = pop!(__overrides, "altitude", nothing); isnothing(__ovr_altitude) || push!(__eqs, altitude ~ __ovr_altitude) + __ovr_altitude__initial = pop!(__overrides, "altitude__initial", nothing); isnothing(__ovr_altitude__initial) || (__initial_conditions[altitude] = __ovr_altitude__initial) + __ovr_altitude__guess = pop!(__overrides, "altitude__guess", nothing) + __ovr_rho = pop!(__overrides, "rho", nothing); isnothing(__ovr_rho) || push!(__eqs, rho ~ __ovr_rho) + __ovr_rho__initial = pop!(__overrides, "rho__initial", nothing); isnothing(__ovr_rho__initial) || (__initial_conditions[rho] = __ovr_rho__initial) + __ovr_rho__guess = pop!(__overrides, "rho__guess", nothing) + __ovr_q = pop!(__overrides, "q", nothing); isnothing(__ovr_q) || push!(__eqs, q ~ __ovr_q) + __ovr_q__initial = pop!(__overrides, "q__initial", nothing); isnothing(__ovr_q__initial) || (__initial_conditions[q] = __ovr_q__initial) + __ovr_q__guess = pop!(__overrides, "q__guess", nothing) + __ovr_A = pop!(__overrides, "A", nothing); isnothing(__ovr_A) || push!(__eqs, A ~ __ovr_A) + __ovr_A__initial = pop!(__overrides, "A__initial", nothing); isnothing(__ovr_A__initial) || (__initial_conditions[A] = __ovr_A__initial) + __ovr_A__guess = pop!(__overrides, "A__guess", nothing) + __ovr_stage = pop!(__overrides, "stage", nothing); isnothing(__ovr_stage) || push!(__eqs, stage ~ __ovr_stage) + __ovr_stage__initial = pop!(__overrides, "stage__initial", nothing); isnothing(__ovr_stage__initial) || (__initial_conditions[stage] = __ovr_stage__initial) + __ovr_stage__guess = pop!(__overrides, "stage__guess", nothing) + __ovr_radial_hat = pop!(__overrides, "radial_hat", nothing); isnothing(__ovr_radial_hat) || push!(__eqs, radial_hat ~ __ovr_radial_hat) + __ovr_radial_hat__initial = pop!(__overrides, "radial_hat__initial", nothing); isnothing(__ovr_radial_hat__initial) || (__initial_conditions[radial_hat] = __ovr_radial_hat__initial) + __ovr_radial_hat__guess = pop!(__overrides, "radial_hat__guess", nothing) + __ovr_downrange_hat = pop!(__overrides, "downrange_hat", nothing); isnothing(__ovr_downrange_hat) || push!(__eqs, downrange_hat ~ __ovr_downrange_hat) + __ovr_downrange_hat__initial = pop!(__overrides, "downrange_hat__initial", nothing); isnothing(__ovr_downrange_hat__initial) || (__initial_conditions[downrange_hat] = __ovr_downrange_hat__initial) + __ovr_downrange_hat__guess = pop!(__overrides, "downrange_hat__guess", nothing) + __ovr_thrust_dir = pop!(__overrides, "thrust_dir", nothing); isnothing(__ovr_thrust_dir) || push!(__eqs, thrust_dir ~ __ovr_thrust_dir) + __ovr_thrust_dir__initial = pop!(__overrides, "thrust_dir__initial", nothing); isnothing(__ovr_thrust_dir__initial) || (__initial_conditions[thrust_dir] = __ovr_thrust_dir__initial) + __ovr_thrust_dir__guess = pop!(__overrides, "thrust_dir__guess", nothing) + __ovr_v_esc = pop!(__overrides, "v_esc", nothing); isnothing(__ovr_v_esc) || push!(__eqs, v_esc ~ __ovr_v_esc) + __ovr_v_esc__initial = pop!(__overrides, "v_esc__initial", nothing); isnothing(__ovr_v_esc__initial) || (__initial_conditions[v_esc] = __ovr_v_esc__initial) + __ovr_v_esc__guess = pop!(__overrides, "v_esc__guess", nothing) + __ovr_spec_energy = pop!(__overrides, "spec_energy", nothing); isnothing(__ovr_spec_energy) || push!(__eqs, spec_energy ~ __ovr_spec_energy) + __ovr_spec_energy__initial = pop!(__overrides, "spec_energy__initial", nothing); isnothing(__ovr_spec_energy__initial) || (__initial_conditions[spec_energy] = __ovr_spec_energy__initial) + __ovr_spec_energy__guess = pop!(__overrides, "spec_energy__guess", nothing) + + ### Constants + __constants = Any[] + + ### Components + # Subcomponent world of type MultibodyComponents.World + world_overrides = __pop_subcomponent_overrides!(__overrides, "world") + push!(__systems, @named world = MultibodyComponents.World(; world_overrides...)) + # Subcomponent body of type JuliaCon2026Components.VariableMassBody + body_overrides = __pop_subcomponent_overrides!(__overrides, "body") + push!(__systems, @named body = JuliaCon2026Components.VariableMassBody(; mu=mu, r_0__initial=[0, R_body, 0], v_0__initial=[0, 0, 0], body_overrides...)) + # Subcomponent thrust of type MultibodyComponents.WorldForce + thrust_overrides = __pop_subcomponent_overrides!(__overrides, "thrust") + push!(__systems, @named thrust = MultibodyComponents.WorldForce(; resolve_in_frame=MultibodyComponents.ResolveInFrame.World(), thrust_overrides...)) + # Subcomponent drag of type MultibodyComponents.WorldForce + drag_overrides = __pop_subcomponent_overrides!(__overrides, "drag") + push!(__systems, @named drag = MultibodyComponents.WorldForce(; resolve_in_frame=MultibodyComponents.ResolveInFrame.World(), drag_overrides...)) + + ### Check there are no unmatched overrides + isempty(__overrides) || throw(ArgumentError("overrides: [$(join(keys(__overrides), ", "))] don't match names found in model. These names may exist in the model but could have been conditionally excluded.")) + + ### Guesses + isnothing(__ovr_mp1__guess) || (__guesses[mp1] = __ovr_mp1__guess) + isnothing(__ovr_mp2__guess) || (__guesses[mp2] = __ovr_mp2__guess) + isnothing(__ovr_m__guess) || (__guesses[m] = __ovr_m__guess) + isnothing(__ovr_Fthrust__guess) || (__guesses[Fthrust] = __ovr_Fthrust__guess) + isnothing(__ovr_phi__guess) || (__guesses[phi] = __ovr_phi__guess) + isnothing(__ovr_rmag__guess) || (__guesses[rmag] = __ovr_rmag__guess) + isnothing(__ovr_vmag__guess) || (__guesses[vmag] = __ovr_vmag__guess) + isnothing(__ovr_altitude__guess) || (__guesses[altitude] = __ovr_altitude__guess) + isnothing(__ovr_rho__guess) || (__guesses[rho] = __ovr_rho__guess) + isnothing(__ovr_q__guess) || (__guesses[q] = __ovr_q__guess) + isnothing(__ovr_A__guess) || (__guesses[A] = __ovr_A__guess) + isnothing(__ovr_stage__guess) || (__guesses[stage] = __ovr_stage__guess) + isnothing(__ovr_radial_hat__guess) || (__guesses[radial_hat] = __ovr_radial_hat__guess) + isnothing(__ovr_downrange_hat__guess) || (__guesses[downrange_hat] = __ovr_downrange_hat__guess) + isnothing(__ovr_thrust_dir__guess) || (__guesses[thrust_dir] = __ovr_thrust_dir__guess) + isnothing(__ovr_v_esc__guess) || (__guesses[v_esc] = __ovr_v_esc__guess) + isnothing(__ovr_spec_energy__guess) || (__guesses[spec_energy] = __ovr_spec_energy__guess) + + ### Initialization Equations + push!(__initialization_eqs, mp1 ~ m1_prop) + push!(__initialization_eqs, mp2 ~ m2_prop) + + ### Assertions + __assertions = [] + + ### Equations + push!(__eqs, ModelingToolkit.D_nounits(mp1) ~ ifelse(mp1 > 0.0, -mdot1, 0.0)) + push!(__eqs, ModelingToolkit.D_nounits(mp2) ~ ifelse(mp1 > 0.0, 0.0, ifelse(mp2 > 0.0, -mdot2, 0.0))) + push!(__eqs, Fthrust ~ ifelse(mp1 > 0.0, mdot1 * ve1, ifelse(mp2 > 0.0, mdot2 * ve2, 0.0))) + push!(__eqs, m ~ ifelse(mp1 > 0.0, m1_dry + mp1 + m2_dry + mp2 + payload, m2_dry + mp2 + payload)) + push!(__eqs, A ~ ifelse(mp1 > 0.0, A_stack, A_orbiter)) + push!(__eqs, stage ~ ifelse(mp1 > 0.0, 1.0, ifelse(mp2 > 0.0, 2.0, 0.0))) + push!(__eqs, rmag ~ sqrt(getindex(getproperty(body, :r_0), 1) ^ 2 + getindex(getproperty(body, :r_0), 2) ^ 2 + getindex(getproperty(body, :r_0), 3) ^ 2)) + push!(__eqs, vmag ~ sqrt(getindex(getproperty(body, :v_0), 1) ^ 2 + getindex(getproperty(body, :v_0), 2) ^ 2 + getindex(getproperty(body, :v_0), 3) ^ 2)) + push!(__eqs, altitude ~ rmag - R_body) + push!(__eqs, radial_hat ~ body.r_0 / rmag) + push!(__eqs, downrange_hat ~ [getindex(getproperty(body, :r_0), 2), -getindex(getproperty(body, :r_0), 1), 0] / rmag) + push!(__eqs, phi ~ ifelse(t < t_vert, 0.0, ifelse(t < t_pitch_end, phi_max * (t - t_vert) / (t_pitch_end - t_vert), phi_max))) + push!(__eqs, thrust_dir ~ cos(phi) * radial_hat + sin(phi) * downrange_hat) + push!(__eqs, rho ~ rho0 * exp(-altitude / Hscale)) + push!(__eqs, q ~ 0.5 * rho * vmag ^ 2) + push!(__eqs, body.m_in ~ m) + push!(__eqs, thrust.force_x ~ Fthrust * thrust_dir[1]) + push!(__eqs, thrust.force_y ~ Fthrust * thrust_dir[2]) + push!(__eqs, thrust.force_z ~ Fthrust * thrust_dir[3]) + push!(__eqs, drag.force_x ~ -Cd * 0.5 * rho * A * vmag * getindex(getproperty(body, :v_0), 1)) + push!(__eqs, drag.force_y ~ -Cd * 0.5 * rho * A * vmag * getindex(getproperty(body, :v_0), 2)) + push!(__eqs, drag.force_z ~ -Cd * 0.5 * rho * A * vmag * getindex(getproperty(body, :v_0), 3)) + push!(__eqs, v_esc ~ sqrt(2 * mu / rmag)) + push!(__eqs, spec_energy ~ 0.5 * vmag ^ 2 - mu / rmag) + push!(__eqs, connect(thrust.frame_b, body.frame_a)) + push!(__eqs, connect(drag.frame_b, body.frame_a)) + + # Return completely constructed System + return System(__eqs, t, __vars, __params; systems=__systems, initial_conditions=__initial_conditions, guesses=__guesses, name, initialization_eqs=__initialization_eqs, bindings=__bindings, assertions=__assertions) +end +export TwoStageRocket diff --git a/generated/TwoStageRocket_experiment.jl b/generated/TwoStageRocket_experiment.jl new file mode 100644 index 0000000..4bb4837 --- /dev/null +++ b/generated/TwoStageRocket_experiment.jl @@ -0,0 +1,7 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + + diff --git a/generated/TwoStageRocket_test.jl b/generated/TwoStageRocket_test.jl new file mode 100644 index 0000000..4bb4837 --- /dev/null +++ b/generated/TwoStageRocket_test.jl @@ -0,0 +1,7 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + + diff --git a/generated/VariableMassBody_definition.jl b/generated/VariableMassBody_definition.jl new file mode 100644 index 0000000..de15149 --- /dev/null +++ b/generated/VariableMassBody_definition.jl @@ -0,0 +1,144 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + +import Moshi as __Ext__Moshi + +@doc Markdown.doc""" + VariableMassBody(; name, mu) + +Free-flying point body with time-varying mass in an inverse-square (point) +gravity field. Translational dynamics only: orientation is held fixed at the +identity so no rotational states are introduced. + +The instantaneous total mass is supplied through the `m_in` signal, so the +staging / propellant logic can live in the enclosing model. External forces +(thrust, drag) enter through `frame_a`; gravity is computed internally from the +absolute position. + +Newton's law in the frame (with R = I, r_cm = 0) mirrors the standard +`MultibodyComponents.Body`: `frame_a.f = m * (a_0 - g_0)`. + +## Parameters: + +| Name | Description | Units | Default value | +| ------------ | ----------------------------------- | ------ | --------------- | +| `mu` | Gravitational parameter of the central body [m^3/s^2] | m3/s2 | 3.986004418e14 | + +## Connectors + + * `frame_a` - Frame3D is the fundamental 3D connector used for 6DOF motion. Most components have one or several `Frame` +connectors that can be connected together ([`Frame3D`](@ref)) + * `m_in` - This connector represents a real signal as an input to a component ([`RealInput`](@ref)) + +## Variables + +| Name | Description | Units | +| ------------ | ----------------------------------- | ------ | +| `r_0` | Absolute position resolved in the world frame | m | +| `v_0` | Absolute velocity resolved in the world frame | m/s | +| `a_0` | Absolute acceleration resolved in the world frame | m/s2 | +| `g_0` | Gravitational acceleration resolved in the world frame | m/s2 | +| `rmag` | Distance from the central body centre | m | +""" +@component function VariableMassBody(; name = nothing, mu=Float64(398600441800000.0), kwargs...) + isnothing(name) && throw(ArgumentError(""" + The `name` keyword must be provided. Please consider using the `@named` macro, + like so: + + @named model = VariableMassBody() + """)) + + __overrides = __build_overrides(kwargs) + __params = Symbolics.SymbolicT[] + __vars = Symbolics.SymbolicT[] + __systems = System[] + __guesses = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + __initial_conditions = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + __initialization_eqs = Equation[] + __eqs = Equation[] + __bindings = Dict{Symbolics.SymbolicT, Symbolics.SymbolicT}() + + ### Structural Parameters (functions) + + ### Structural Parameters (Final) + + ### Path Parameters (functions) + + ### Path Parameters (non-final) + + ### Final Parameters (declarations) + + ### Deferred assignment (default values that depend on final parameters) + + ### Symbolic Parameters + __local__mu = mu + append!(__params, @parameters (mu::Real), [description = "Gravitational parameter of the central body [m^3/s^2]"]) + __initial_conditions[mu] = __local__mu + + ### Final Parameters (assignments) + + ### Final Path Parameters + append!(__vars, @variables (m_in(t)::Real), [input = true]) + + ### Variables (declarations) + append!(__vars, @variables (r_0(t)[1:3]::Real), [description = "Absolute position resolved in the world frame"]) + append!(__vars, @variables (v_0(t)[1:3]::Real), [description = "Absolute velocity resolved in the world frame"]) + append!(__vars, @variables (a_0(t)[1:3]::Real), [description = "Absolute acceleration resolved in the world frame"]) + append!(__vars, @variables (g_0(t)[1:3]::Real), [description = "Gravitational acceleration resolved in the world frame"]) + append!(__vars, @variables (rmag(t)::Real), [description = "Distance from the central body centre"]) + + ### Variables (assignments) + __ovr_r_0 = pop!(__overrides, "r_0", nothing); isnothing(__ovr_r_0) || push!(__eqs, r_0 ~ __ovr_r_0) + __ovr_r_0__initial = pop!(__overrides, "r_0__initial", nothing); isnothing(__ovr_r_0__initial) || (__initial_conditions[r_0] = __ovr_r_0__initial) + __ovr_r_0__guess = pop!(__overrides, "r_0__guess", nothing) + __ovr_v_0 = pop!(__overrides, "v_0", nothing); isnothing(__ovr_v_0) || push!(__eqs, v_0 ~ __ovr_v_0) + __ovr_v_0__initial = pop!(__overrides, "v_0__initial", nothing); isnothing(__ovr_v_0__initial) || (__initial_conditions[v_0] = __ovr_v_0__initial) + __ovr_v_0__guess = pop!(__overrides, "v_0__guess", nothing) + __ovr_a_0 = pop!(__overrides, "a_0", nothing); isnothing(__ovr_a_0) || push!(__eqs, a_0 ~ __ovr_a_0) + __ovr_a_0__initial = pop!(__overrides, "a_0__initial", nothing); isnothing(__ovr_a_0__initial) || (__initial_conditions[a_0] = __ovr_a_0__initial) + __ovr_a_0__guess = pop!(__overrides, "a_0__guess", nothing) + __ovr_g_0 = pop!(__overrides, "g_0", nothing); isnothing(__ovr_g_0) || push!(__eqs, g_0 ~ __ovr_g_0) + __ovr_g_0__initial = pop!(__overrides, "g_0__initial", nothing); isnothing(__ovr_g_0__initial) || (__initial_conditions[g_0] = __ovr_g_0__initial) + __ovr_g_0__guess = pop!(__overrides, "g_0__guess", nothing) + __ovr_rmag = pop!(__overrides, "rmag", nothing); isnothing(__ovr_rmag) || push!(__eqs, rmag ~ __ovr_rmag) + __ovr_rmag__initial = pop!(__overrides, "rmag__initial", nothing); isnothing(__ovr_rmag__initial) || (__initial_conditions[rmag] = __ovr_rmag__initial) + __ovr_rmag__guess = pop!(__overrides, "rmag__guess", nothing) + + ### Constants + __constants = Any[] + + ### Components + push!(__systems, @named frame_a = __Dyad__Frame3D()) + + ### Check there are no unmatched overrides + isempty(__overrides) || throw(ArgumentError("overrides: [$(join(keys(__overrides), ", "))] don't match names found in model. These names may exist in the model but could have been conditionally excluded.")) + + ### Guesses + isnothing(__ovr_r_0__guess) || (__guesses[r_0] = __ovr_r_0__guess) + isnothing(__ovr_v_0__guess) || (__guesses[v_0] = __ovr_v_0__guess) + isnothing(__ovr_a_0__guess) || (__guesses[a_0] = __ovr_a_0__guess) + isnothing(__ovr_g_0__guess) || (__guesses[g_0] = __ovr_g_0__guess) + isnothing(__ovr_rmag__guess) || (__guesses[rmag] = __ovr_rmag__guess) + + ### Initialization Equations + + ### Assertions + __assertions = [] + + ### Equations + push!(__eqs, r_0 ~ frame_a.r_0) + push!(__eqs, v_0 ~ ModelingToolkit.D_nounits(r_0)) + push!(__eqs, a_0 ~ ModelingToolkit.D_nounits(v_0)) + push!(__eqs, frame_a.R ~ [1 0 0; 0 1 0; 0 0 1]) + push!(__eqs, frame_a.tau ~ [0, 0, 0]) + push!(__eqs, rmag ~ sqrt(r_0[1] ^ 2 + r_0[2] ^ 2 + r_0[3] ^ 2)) + push!(__eqs, g_0 ~ (-mu / rmag ^ 3) * r_0) + push!(__eqs, frame_a.f ~ m_in * (a_0 - g_0)) + + # Return completely constructed System + return System(__eqs, t, __vars, __params; systems=__systems, initial_conditions=__initial_conditions, guesses=__guesses, name, initialization_eqs=__initialization_eqs, bindings=__bindings, assertions=__assertions) +end +export VariableMassBody diff --git a/generated/VariableMassBody_experiment.jl b/generated/VariableMassBody_experiment.jl new file mode 100644 index 0000000..4bb4837 --- /dev/null +++ b/generated/VariableMassBody_experiment.jl @@ -0,0 +1,7 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + + diff --git a/generated/VariableMassBody_test.jl b/generated/VariableMassBody_test.jl new file mode 100644 index 0000000..4bb4837 --- /dev/null +++ b/generated/VariableMassBody_test.jl @@ -0,0 +1,7 @@ +### DO NOT EDIT THIS FILE +### This file is auto-generated by the Dyad command-line compiler. +### If you edit this code it is likely to get overwritten. +### Instead, update the Dyad source code and regenerate this file + + + diff --git a/generated/definitions.jl b/generated/definitions.jl index ddf3423..9eb1c13 100644 --- a/generated/definitions.jl +++ b/generated/definitions.jl @@ -16,7 +16,15 @@ if isfile(joinpath((@__DIR__) |> Base.dirname, "dyad", "definitions.jl")) include(joinpath((@__DIR__) |> Base.dirname, "dyad", "definitions.jl")) end +import BlockComponents +import DyadData import DyadInterface +import ElectricalComponents +import HydraulicComponents +import MultibodyComponents +import RotationalComponents +import ThermalComponents +import TranslationalComponents @doc Markdown.doc""" This connector represents an electrical pin with voltage and current as the potential and flow variables, respectively. """ @@ -196,4 +204,9 @@ end include("Hello_definition.jl") +include("LaunchToEscape_definition.jl") +include("TestOrbitTransient_definition.jl") +include("TestOrbit_definition.jl") +include("TwoStageRocket_definition.jl") +include("VariableMassBody_definition.jl") include("World_definition.jl") \ No newline at end of file diff --git a/generated/experiments.jl b/generated/experiments.jl index 93c4626..b473eb3 100644 --- a/generated/experiments.jl +++ b/generated/experiments.jl @@ -9,4 +9,7 @@ if isfile(joinpath((@__DIR__) |> Base.dirname, "dyad", "experiments.jl")) end -include("Hello_experiment.jl") \ No newline at end of file +include("Hello_experiment.jl") +include("TestOrbit_experiment.jl") +include("TwoStageRocket_experiment.jl") +include("VariableMassBody_experiment.jl") \ No newline at end of file diff --git a/generated/tests.jl b/generated/tests.jl index 1ac7d46..306af93 100644 --- a/generated/tests.jl +++ b/generated/tests.jl @@ -19,4 +19,7 @@ include("test_internals.jl") @testset "`JuliaCon2026Components`" begin include("Hello_test.jl") +include("TestOrbit_test.jl") +include("TwoStageRocket_test.jl") +include("VariableMassBody_test.jl") end \ No newline at end of file diff --git a/viz_submission/index.html b/viz_submission/index.html new file mode 100644 index 0000000..4440a43 --- /dev/null +++ b/viz_submission/index.html @@ -0,0 +1,472 @@ + + +
+ + +