Files
rocketry/docs/SOLVER.md
2026-03-04 20:29:19 +00:00

8.8 KiB

Solver Guide

Overview

The Equation Solver is a constraint-based computational engine that automatically solves rocket propulsion equations. Rather than manually plugging numbers into formulas, users specify constraints (inputs), and the solver propagates solutions through an interconnected equation network.

Key Concept: Drag variables onto the workspace, set values, and the solver automatically computes unknowns.

User Interface

Variable Palette (Left)

  • Searchable list of all variables
  • Organized by category (thrust, Isp, chamber, etc.)
  • Drag variables onto workspace

Workspace (Center)

  • Drop zone for constraint cards
  • Cards show variable name, unit, input field
  • Set constraint by entering value
  • Results auto-compute below

Results Panel (Right)

  • Shows all computed values
  • Organized by category
  • Clickable to copy values
  • Unit selector for each variable

Constraint Propagation Algorithm

The solver implements greedy propagation:

Step-by-Step

  1. User Input: Sets constraint on variable x
  2. Find Equations: Locates all equations referencing x
  3. Attempt Solve: For each equation, tries to solve for unknowns
    • If equation has 1 unknown: solve directly
    • If equation has 2+ unknowns: skip (not enough constraints)
  4. Update State: Newly-solved variables are added to known set
  5. Recurse: Repeat step 2 with newly-known variables
  6. Stop: When no new variables can be computed

Example

Given:

  • thrust = massFlowRate * exitVelocity
  • exitVelocity = sqrt(2 * Cp * (T0 - Te))
  • massFlowRate = densityO2 * densityFuel * burnRate

User Constraints:

  • thrust = 50000 N
  • massFlowRate = 100 kg/s

Solver Flow:

1. Set thrust = 50000
2. Find equations with thrust: Eq1
3. Eq1 has 2 unknowns (massFlowRate, exitVelocity) → skip
4. Set massFlowRate = 100
5. Find equations with massFlowRate: Eq1, Eq3
6. Eq1 now has 1 unknown (exitVelocity) → solve: exitVelocity = 500 m/s
7. Find equations with exitVelocity: Eq2
8. Eq2 has 2 unknowns (T0, Te) → skip
9. No new variables → done

Variable Definitions

Variables are defined in src/engine/variables.js with metadata:

{
  id: 'thrust',
  name: 'Thrust',
  unit: 'N',
  category: 'performance',
  type: 'number'
}

Categories:

  • thrust — Force (N, lbf)
  • isp — Specific impulse (s, m/s)
  • chamber — Chamber conditions (P, T, density)
  • nozzle — Nozzle geometry (area, diameter, angle)
  • propellant — Fuel/oxidizer properties
  • flow — Mass flow rate, burn rate
  • thermal — Heat, temperature
  • structural — Stress, strain, thickness

Equation Library

Equations are defined in src/engine/equations.js. Each equation:

  1. Specifies variables it relates
  2. Implements forward solver (compute output given inputs)
  3. Implements per-variable solvers (solve for each variable given others)

Example Equation

{
  id: 'thrustEquation',
  name: 'Thrust (Momentum)',
  variables: ['thrust', 'massFlowRate', 'exitVelocity'],
  equation: 'thrust = massFlowRate * exitVelocity',
  forward: (inputs) => {
    return inputs.massFlowRate * inputs.exitVelocity
  },
  solvers: {
    exitVelocity: (inputs) => {
      return inputs.thrust / inputs.massFlowRate
    },
    thrust: (inputs) => {
      return inputs.massFlowRate * inputs.exitVelocity
    }
  }
}

Transcendental Equations (Bisection)

For equations with no closed-form solution (e.g., Mach from area ratio), the solver uses bisection:

// In numerics.js
function bisection(fn, target, min, max, tolerance) {
  while (max - min > tolerance) {
    const mid = (min + max) / 2
    const fMid = fn(mid)
    if (fMid < target) {
      min = mid
    } else {
      max = mid
    }
  }
  return (min + max) / 2
}

Example: Finding Mach number from area ratio

solvers: {
  machNumber: (inputs) => {
    const fn = (M) => isentropicAreaRatio(M, inputs.gamma)
    return bisection(fn, inputs.areaRatio, 0.01, 10, 1e-6)
  }
}

Common Equations

Thrust

thrust = mass_flow_rate * exit_velocity
thrust = chamber_pressure * throat_area * CF

Specific Impulse

Isp = exit_velocity / g
Isp_vac = exit_velocity / g
Isp_sl = (exit_velocity - P_exit / mass_flow_rate * area_exit) / g

Chamber Conditions (Isentropic Flow)

T_exit = T_chamber * (P_exit / P_chamber)^((gamma - 1) / gamma)
rho_exit = rho_chamber * (P_exit / P_chamber)^(1 / gamma)

Nozzle Area Ratio

A_exit / A_throat = (2 / (gamma + 1)) * (1 + (gamma - 1)/2 * M_exit^2))^((gamma + 1) / (2 * (gamma - 1))) / M_exit

(requires bisection to invert for M)

Characteristic Velocity

c_star = P_chamber * A_throat / mass_flow_rate

Thrust Coefficient

CF = sqrt(2 * gamma^2 / (gamma - 1) * (2 / (gamma + 1))^((gamma + 1) / (gamma - 1)) * (1 - (P_exit / P_chamber)^((gamma - 1) / gamma)))

Workflow Examples

Example 1: Determine Exit Velocity from Isp

Goal: Calculate exit velocity given Isp

Steps:

  1. Drag specificImpulse onto workspace
  2. Set specificImpulse = 300 s
  3. Solver computes exitVelocity = 300 * 9.81 ≈ 2943 m/s

Example 2: Find Chamber Pressure from Thrust

Goal: Find chamber pressure needed for 50 kN thrust

Steps:

  1. Drag thrust, throatDiameter, massFlowRate onto workspace
  2. Set:
    • thrust = 50000 N
    • throatDiameter = 0.1 m
    • massFlowRate = 100 kg/s
  3. Solver finds equations with these variables
  4. Uses thrust equation to find thrust coefficient needed
  5. Inverts nozzle area ratio with bisection to find Mach
  6. Uses isentropic relations to find chamber pressure
  7. Displays chamberPressure = X bar

Example 3: Design for Specific Isp

Goal: Find propellant combination for Isp = 350 s

Steps:

  1. Drag specificImpulse, chamberTemperature, exhaustGamma onto workspace
  2. Set specificImpulse = 350 s
  3. Click on knowledgebase to find propellant with T0 ≈ 3500 K
  4. Enter that temperature
  5. Solver computes exitVelocity, then works backward to required conditions
  6. Compare against available propellants

Advanced Features

Unit Conversion

Every variable card has a unit selector. Setting a variable automatically converts:

thrust = 50000 N → 11240.44 lbf
thrust = 11240.44 lbf → 50000 N

Importing Engine Design

Engine design results can be fed into the solver:

  • File → Import Engine JSON
  • Automatically populates thrust, Isp, chamber pressure, etc.
  • Enables end-to-end rocket design workflow

Variable Categories

Filter variables by category to reduce clutter:

  • Thrust (F, Isp, c*)
  • Chamber (P, T, density)
  • Nozzle (area, geometry)
  • Propellant (fuel/oxidizer properties)
  • Flow (mass flow, burn rate)

Limitations & Gotchas

  1. No Circular Dependencies: If equations form a cycle, solver may loop infinitely

    • Solver stops after N iterations to prevent this
    • Design equations to be acyclic where possible
  2. Insufficient Constraints: If variables are underdetermined (more unknowns than equations)

    • Solver computes what it can, leaves rest as unknown
    • User must provide more constraints
  3. Overdetermined System: If too many constraints (conflicting values)

    • Solver uses first constraint encountered
    • Other constraints ignored (may warn in future)
  4. Transcendental Equation Tolerance: Bisection has numerical error

    • Default tolerance: 1e-6
    • Results accurate to ~6 significant figures
    • Adjust in numerics.js if higher precision needed

Troubleshooting

Solver not computing?

  • Ensure at least one constraint is set
  • Check that equation network connects the variables you're trying to solve
  • Look for missing material properties (fuel, oxidizer data)

Result seems wrong?

  • Verify input units match variable definition
  • Check variable category (is it the right variable?)
  • Try solving step-by-step with intermediate variables

Equation not available?

  • Not all rocketry equations are implemented
  • Submit a feature request to add more
  • Or add the equation yourself in src/engine/equations.js

Development Guide

Adding a New Equation

  1. Define variables in variables.js if needed
  2. Implement equation in equations.js:
equations.push({
  id: 'myEquation',
  name: 'My Equation',
  variables: ['var1', 'var2', 'var3'],
  equation: 'var1 = var2 * var3',
  solvers: {
    var1: (inputs) => inputs.var2 * inputs.var3,
    var2: (inputs) => inputs.var1 / inputs.var3,
    var3: (inputs) => inputs.var1 / inputs.var2
  }
})
  1. Test by:
    • Setting constraints manually
    • Verifying solver produces correct result
    • Testing with known values

Debugging Solver

  • Add console logs in solver.js propagation loop
  • Log variable state at each iteration
  • Verify equation network is correct

Last Updated: 2025-02 | Status: Current