API reference¶
The public surface is the ten names importable from orlab, plus the
exception types in orlab.errors, the jar utilities in orlab.jars, the
parallel-running machinery in orlab.parallel, and the dispersion
listeners in orlab.listeners. Everything else is internal.
OpenRocketInstance¶
Use with the 'with' construct: entering starts the JVM and OpenRocket
on first use. The JVM cannot be restarted in a process (JPype), so it
stays up after the block and ends with the interpreter — a later
with OpenRocketInstance(...) on the same jar reuses it (sequential
blocks and notebook re-runs work); a different jar raises OrlabError.
OpenRocket's log level is process-global: the most recently entered
instance's log_level wins.
Source code in src/orlab/core/openrocket_instance.py
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | |
__init__(jar_path=None, log_level=OrLogLevel.ERROR, *, jvm_path=None, jvm_args=())
¶
jar_path is the full path of the OpenRocket .jar file to use; defaults to $ORLAB_JAR, then $CLASSPATH, then the newest supported OpenRocket-*.jar in the current directory, then the newest jar in the orlab.fetch_jar cache (verified, never downloading). log_level can be either OFF, ERROR, WARN, INFO, DEBUG, TRACE and ALL. jvm_path selects the JVM library explicitly (default: JPype's auto-detection via JAVA_HOME). jvm_args are appended to the JVM launch arguments, e.g. ("-Xmx4g",) for large monte-carlo runs; both only take effect for the instance that actually starts the JVM.
Source code in src/orlab/core/openrocket_instance.py
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | |
Helper¶
This class contains a variety of useful helper functions and wrapper for using openrocket via jpype. These are intended to take care of some of the more cumbersome aspects of calling methods, or provide more 'pythonic' data structures for general use.
Source code in src/orlab/core/helper.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | |
load_doc(or_filename)
¶
Loads a .ork file and returns the corresponding openrocket document
Source code in src/orlab/core/helper.py
53 54 55 56 57 58 59 | |
save_doc(or_filename, doc)
¶
Saves an openrocket document to a .ork file
Source code in src/orlab/core/helper.py
61 62 63 64 65 66 | |
run_simulation(sim, listeners=None, *, randomize_seed=True)
¶
This is a wrapper to the Simulation.simulate() for running a simulation The optional listeners parameter is a sequence of objects which extend orl.AbstractSimulationListener.
By default the simulation's random seed is randomized before each run (identical repeated runs would otherwise produce identical numbers — the behavior naive monte-carlo loops rely on). Pass randomize_seed=False to respect the seed already set on the options. Note: on OpenRocket 24.12 the wind model draws additional per-process entropy, so a fixed seed reproduces results within one process but not across processes when wind is enabled.
Source code in src/orlab/core/helper.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
translate_flight_data_type(flight_data_type)
¶
Translates a FlightDataType (or constant name) to the Java constant. Raises UnsupportedFlightDataType when the loaded OpenRocket version does not expose it (constants differ across versions).
Source code in src/orlab/core/helper.py
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
get_timeseries(simulation, variables, branch_number=0)
¶
Gets a dictionary of timeseries data (as numpy arrays) from a simulation given specific variable names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
simulation
|
An openrocket simulation object. |
required | |
variables
|
Iterable[FlightDataType | str]
|
A sequence of FlightDataType or strings representing the desired variables |
required |
branch_number
|
Stage branch to read (0 = sustainer). |
0
|
Returns:
| Type | Description |
|---|---|
dict[FlightDataType | str, ndarray]
|
Dict keyed by the requested variables; values are numpy arrays. |
Source code in src/orlab/core/helper.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | |
get_final_values(simulation, variables, branch_number=0)
¶
Gets a the final value in the time series from a simulation given variable names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
simulation
|
An openrocket simulation object. |
required | |
variables
|
Iterable[FlightDataType | str]
|
A sequence of FlightDataType or strings representing the desired variables |
required |
branch_number
|
Stage branch to read (0 = sustainer). |
0
|
Returns:
| Type | Description |
|---|---|
dict[FlightDataType | str, float]
|
Dict keyed by the requested variables; values are the final samples. |
Source code in src/orlab/core/helper.py
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |
translate_flight_event(flight_event)
¶
Translates a Java FlightEvent.Type constant to the FlightEvent enum. Raises ValueError for event types this orlab version does not know (newer OpenRocket releases add types; get_events skips them instead).
Source code in src/orlab/core/helper.py
171 172 173 174 175 176 177 178 179 180 181 182 | |
get_events(simulation, branch_number=0)
¶
Returns a dictionary of all the flight events in a given simulation. Key is FlightEvent and value is a list of all the times at which the event occurs. Event types not known to this orlab version are skipped with a warning.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
branch_number
|
int
|
Stage branch to read (0 = sustainer). |
0
|
Source code in src/orlab/core/helper.py
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
get_summary(simulation, branch_number=0)
¶
Returns the scalar flight report for one branch as a
:class:~orlab.FlightSummary — plain-Python values only, safe to
pickle into JVM-less processes.
Branch 0 uses OpenRocket's own FlightData summary getters verbatim; other branches derive the same numbers from their own time series. Missing/inapplicable values are NaN (see the field docs). Degenerate flights degrade to NaN; an unsimulated simulation raises OrlabError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
branch_number
|
int
|
Stage branch to summarize (0 = sustainer). |
0
|
Source code in src/orlab/core/helper.py
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | |
get_dataframe(simulation, variables=None, branch_number=0)
¶
The branch's timeseries as a pandas DataFrame, one column per
variable, labeled NAME (SI unit). Requires the orlab[pandas]
extra; everything else in orlab works without pandas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variables
|
FlightDataTypes or constant names; default: every profile data type populated on the branch. |
None
|
|
branch_number
|
int
|
Stage branch to read (0 = sustainer). |
0
|
Source code in src/orlab/core/helper.py
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | |
export_csv(simulation, path, variables=None, branch_number=0)
¶
Writes the branch's timeseries as UTF-8 CSV with NAME (SI
unit) headers — stdlib only, no pandas needed. NaN samples become
empty cells (pandas.read_csv reads them back as NaN).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variables
|
FlightDataTypes or constant names; default: every profile data type populated on the branch. |
None
|
|
branch_number
|
int
|
Stage branch to read (0 = sustainer). |
0
|
Source code in src/orlab/core/helper.py
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 | |
get_motor(sim, mount=None)
¶
The designation of the motor the simulation would fly on the given (or auto-resolved) mount, as a plain string; None when the sim's configuration has no motor there.
Source code in src/orlab/core/helper.py
538 539 540 541 542 543 544 545 546 | |
find_motor(designation, manufacturer=None)
¶
A motor from OpenRocket's own database by designation
(case-insensitive exact). Common hobby designations (A8, B6, C6…)
exist from several manufacturers — those lookups require
manufacturer= (motor choice is safety-relevant; orlab refuses to
guess); manufacturer matching uses OpenRocket's own alias machinery,
so "CTI" finds Cesaroni. One manufacturer's designation can span
several motor sets (different diameters/lengths): sets are ordered
by diameter, then length, and the first variant of the first set is
returned — OpenRocket keeps each set's variants deterministically
sorted, so 'the' motor is stable across runs.
Raises:
| Type | Description |
|---|---|
ValueError
|
no match (message lists near-matches), a
designation that exists but not from the given manufacturer, or
an ambiguous designation without |
Source code in src/orlab/core/helper.py
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | |
load_motor(motor_file, designation=None)
¶
A motor loaded from a thrust-curve file (.eng/.rse/.zip) via
OpenRocket's own loader — no database needed, works on every
supported version and startup path. Files holding several motors
need designation= to pick one.
Raises:
| Type | Description |
|---|---|
OrlabError
|
the file doesn't parse as a motor file. |
Source code in src/orlab/core/helper.py
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 | |
set_motor(sim, motor, *, mount=None, manufacturer=None, designation=None, delay=None)
¶
Sets the motor the simulation will actually fly — always keyed on
the sim's own flight configuration (assigning to the rocket's
selected config is the ecosystem's classic silent failure). The
motor argument is a designation string (database lookup, see
:meth:find_motor), a .eng/.rse/.zip path (file load,
see :meth:load_motor), or a ThrustCurveMotor object. delay=
sets the ejection delay in seconds; None preserves the existing one.
The assignment is read back and verified — a mismatch raises instead
of failing silently.
Source code in src/orlab/core/helper.py
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 | |
get_components_of_type(root, component_type)
¶
Every component under root of a given type — a class name string ("BodyTube", "TrapezoidFinSet", "MotorMount", …) resolved against the loaded OpenRocket, or a JClass. Concrete classes, superclasses, and interfaces all match; an empty list is a normal answer.
Raises:
| Type | Description |
|---|---|
ValueError
|
an unknown class name (named with the loaded version — component classes differ across OpenRocket releases). |
Source code in src/orlab/core/helper.py
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 | |
get_component_named(root, name)
¶
Finds and returns the first rocket component with the given name. Requires a root RocketComponent, usually this will be a RocketComponent.rocket instance. Raises a ValueError if no component found.
Source code in src/orlab/core/helper.py
725 726 727 728 729 730 731 732 733 734 | |
get_all_components(root)
¶
Returns a list of all rocket components in the loaded OpenRocket file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root
|
The root RocketComponent (usually obtained from the simulation) |
required |
Returns:
| Type | Description |
|---|---|
list[JObject]
|
List of all component objects |
Source code in src/orlab/core/helper.py
736 737 738 739 740 741 742 743 744 745 | |
AbstractSimulationListener¶
Python implementation of OpenRocket's AbstractSimulationListener.
Subclass it, override the hooks you need, and pass instances to
Helper.run_simulation(sim, listeners=[...]).
OpenRocket clones listeners before the run, so collect results through
shared mutable state (e.g. a list the caller keeps a reference to), not
by assigning to self and reading it back afterwards. Exceptions
raised inside a hook propagate out of run_simulation intact.
Hook groups: SimulationListener (startSimulation, postStep, …),
SimulationEventListener (handleFlightEvent, …), and
SimulationComputationListener (preWindModel,
postAerodynamicCalculation, …). Boolean-returning hooks continue the
simulation/event on True; pre-computation hooks return an override value
or None/NaN to leave OpenRocket's computation untouched.
Source code in src/orlab/core/simulation_listener.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | |
JIterator¶
Wraps a Java iterable as a Python iterator.
Built for walking a rocket's component tree:
for component in JIterator(rocket): print(component.getName())
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
jit
|
any Java object exposing |
required |
Source code in src/orlab/core/jiterator.py
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
FlightSummary¶
Scalar summary of one simulated flight branch.
All values are builtin floats/ints/strs (never Java or numpy types), in
SI units per :attr:UNITS. Missing or inapplicable values are
math.nan, never None — a booster branch has no launch rod
departure, pre-23.09 OpenRocket computes no optimum delay, a flight
without a recovery event has no descent rate. The field set only grows;
pickles are same-orlab-version transport, not an archive format.
Source code in src/orlab/core/summary.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |
velocity_off_rod
instance-attribute
¶
Speed when leaving the launch rod (m/s); NaN on branches without a LAUNCHROD event (boosters).
stability_off_rod_cal
instance-attribute
¶
Stability margin (calibers) at launch rod departure; NaN without a LAUNCHROD event.
apogee
instance-attribute
¶
Highest altitude above the launch site (m).
time_to_apogee
instance-attribute
¶
Time from liftoff to apogee (s).
max_velocity
instance-attribute
¶
Largest total velocity (m/s).
max_acceleration
instance-attribute
¶
Largest total acceleration (m/s²).
max_mach
instance-attribute
¶
Largest Mach number.
min_stability_cal
instance-attribute
¶
Smallest stability margin (calibers) between launch rod departure and apogee. The window matters: OpenRocket 24.12 computes stability through post-apogee tumble, where unwindowed minima are meaningless.
max_stability_cal
instance-attribute
¶
Largest stability margin (calibers) in the same window.
velocity_at_deployment
instance-attribute
¶
Total velocity at the last recovery device deployment (m/s); NaN without a deployment.
descent_rate
instance-attribute
¶
Sample mean of vertical descent speed (m/s, positive down) over the samples from the last recovery device deployment to ground hit; NaN without a deployment.
ground_hit_velocity
instance-attribute
¶
Speed at ground contact (m/s).
landing_x
instance-attribute
¶
Landing position east of the launch site (m, flat-earth).
landing_y
instance-attribute
¶
Landing position north of the launch site (m, flat-earth).
landing_distance
instance-attribute
¶
Straight-line distance from launch site to landing (m).
landing_bearing_deg
instance-attribute
¶
Compass bearing from launch site to landing (degrees, 0 = north, 90 = east). Numerically defined but physically meaningless when landing_distance ≈ 0.
flight_time
instance-attribute
¶
Total simulated flight time (s).
optimum_delay
instance-attribute
¶
OpenRocket's optimum ejection delay (s); NaN before OpenRocket 23.09, which does not compute it.
branch_number
instance-attribute
¶
Which stage branch this summary describes (0 = sustainer).
branch_name
instance-attribute
¶
OpenRocket's name for the branch (e.g. "Sustainer").
branch_count
instance-attribute
¶
How many branches the simulation produced.
warnings
instance-attribute
¶
Simulation warnings, verbatim from OpenRocket (opaque strings).
to_dict()
¶
The summary as a flat dict — one dispersion-study row.
pandas.DataFrame([s.to_dict() for s in summaries]) is the table.
Source code in src/orlab/core/summary.py
139 140 141 142 143 | |
Jar management¶
Downloads (or returns the cached copy of) the OpenRocket jar for
version, verified by sha256. version=None means the default,
orlab._pins.DEFAULT_VERSION.
Versions orlab pins are verified against the shipped pin. Any other
version requires sha256= — compute it yourself from a copy you
trust; there is no way to skip verification.
Raises:
| Type | Description |
|---|---|
JarVerificationError
|
no digest to verify against, or a downloaded jar whose digest does not match (a corrupt cached entry is evicted and re-downloaded once first). |
ValueError
|
a malformed version string or digest, or |
Source code in src/orlab/jars.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
The directory fetch_jar caches jars in: $ORLAB_JAR_CACHE,
else $XDG_CACHE_HOME/orlab-jars, else ~/.cache/orlab-jars.
Source code in src/orlab/jars.py
40 41 42 43 44 45 46 47 48 49 | |
Enums¶
orlab.FlightDataType
¶
Bases: Enum
Flight-data series selectable in Helper.get_timeseries / get_final_values — the union across all supported OpenRocket versions. Requesting one the loaded version lacks raises UnsupportedFlightDataType naming the versions that have it.
Source code in src/orlab/_enums.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | |
orlab.FlightEvent
¶
Bases: Enum
Flight events returned by Helper.get_events — the union across all supported OpenRocket versions (SIM_WARN/SIM_ABORT are 24.12+). Unknown event types from newer jars are skipped with a warning.
Source code in src/orlab/_enums.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
orlab.OrLogLevel
¶
Bases: Enum
OpenRocket's logback log levels, for OpenRocketInstance(log_level=...).
Source code in src/orlab/_enums.py
15 16 17 18 19 20 21 22 23 24 | |
FlightDataType and FlightEvent are generated as the union of constants
across all supported OpenRocket versions; availability on the loaded version
is enforced at translation time with UnsupportedFlightDataType.
Parallel running and declarative options¶
Parallel simulation running and the declarative options contract.
SimulationPool runs dispersion studies across worker processes — one
JVM plus one loaded .ork per worker (JPype allows one JVM per process,
so parallelism is multi-process by construction). Tasks are plain
mappings of DECLARATIVE_KEYS (portable, validated, notebook-safe) or an
importable worker_fn for anything the whitelist doesn't cover. Results
come back as plain-Python records; per-task failures are data, and every
abort path preserves the partial results collected so far.
DECLARATIVE_KEYS is the curated set of SimulationOptions knobs that
are verified to apply-and-read-back identically on every supported
OpenRocket version (15.03, 22.02, 23.09, 24.12 — probed per release, and
re-checked by the profile contract manifest and an all-version integration
case).
One interaction to know: OpenRocket launches into the wind by default, and
while launch_into_wind is true the rod-direction getter reports the
into-wind direction — launch_rod_direction only takes effect together
with launch_into_wind: False (verified on all four versions; the pool
refuses a task set that varies the direction without pinning the flag).
DeclarativeKey
¶
Bases: NamedTuple
How one declarative key maps onto SimulationOptions.
Source code in src/orlab/parallel.py
51 52 53 54 55 56 57 | |
SimResult
dataclass
¶
One successful simulation in a study.
Source code in src/orlab/parallel.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
index
instance-attribute
¶
Submission order (results are returned sorted by this).
task
instance-attribute
¶
The task mapping as submitted.
seed
instance-attribute
¶
The seed the simulation actually used, read back after the run.
seed_reassigned
instance-attribute
¶
True when the readback differs from the pool-assigned seed — e.g. a worker_fn that called run_simulation with randomize_seed=True. The recorded seed is still the authoritative one for replay.
payload
instance-attribute
¶
The default extractor's summary fields, or worker_fn's return value. Always plain-Python data (pickle-checked in the worker).
SimError
dataclass
¶
One failed simulation in a study — failure as data, not an abort.
Source code in src/orlab/parallel.py
104 105 106 107 108 109 110 111 112 113 114 115 | |
StudyResult
dataclass
¶
Everything a study produced, in submission order.
Source code in src/orlab/parallel.py
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | |
to_records()
¶
Flat dicts (task keys + payload + seed/index) — a dispersion
table is pandas.DataFrame(study.to_records()). Column precedence
on name collisions: the reserved index/seed/
seed_reassigned columns override task keys, and payload keys
override both (the declarative path is collision-free by
construction).
Source code in src/orlab/parallel.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
raise_if_errors()
¶
Returns self, or raises OrlabError describing the first failure when any task errored.
Source code in src/orlab/parallel.py
144 145 146 147 148 149 150 151 152 153 154 | |
SimulationPool
¶
A spawn-based worker pool for dispersion studies: each worker boots
one JVM, loads the .ork once, and runs many simulations against it.
Constructing the pool validates everything cheap (jar, document,
simulation index); workers boot lazily on the first :meth:run. Use
from a script's if __name__ == "__main__": block — a requirement of
multiprocessing's spawn start method, which is the only start method
that is safe with a JVM and uniform across platforms.
Source code in src/orlab/parallel.py
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | |
__init__(ork_file, jar_path=None, *, simulation_index=0, max_workers=None, log_level=OrLogLevel.ERROR, jvm_path=None, jvm_args=(), max_tasks_per_child=None, worker_stdout='discard', _test_init=None)
¶
ork_file/jar_path resolve exactly like OpenRocketInstance (the default jar resolution chain applies) but are pinned to absolute paths here — workers never re-run environment-dependent resolution. max_workers defaults to min(4, cpu_count), clamped to the first run's task count; each worker holds a JVM (hundreds of MB — size jvm_args=("-Xmx512m",) accordingly). max_tasks_per_child recycles workers (Python 3.11+). worker_stdout='discard' silences worker stdout including the JVM's native writes on POSIX (best-effort on Windows); stderr is always inherited.
Source code in src/orlab/parallel.py
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | |
run(tasks, *, worker_fn=None, seed=None, progress=None, on_error='collect')
¶
Runs one task per simulation and collects the results.
tasks: an iterable of mappings (DECLARATIVE_KEYS names, plus an
optional reserved 'seed'), or an int meaning that many runs of the
document as-is. worker_fn(helper, sim, task): an importable,
module-level callable taking over the whole task body — set options
yourself (everything you vary), run the simulation, return
plain-Python data. seed: study seed for reproducible seed
derivation; default draws from SystemRandom. progress(done, total):
called with (0, total) up front — JVM boot takes seconds and bars
should render — then once per completion; wrap
pool.run(...)'s completions with tqdm by passing
progress=lambda done, total: bar.update(...) or iterate
to_records afterwards. on_error: 'collect' (failures are SimError
data) or 'abort' (first failure cancels the study).
Raises:
| Type | Description |
|---|---|
StudyAborted
|
interrupt / worker-crash / worker-init /
task-error (with |
Source code in src/orlab/parallel.py
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | |
shutdown()
¶
Stops the workers (their JVMs end with their processes). The pool cannot be reused afterwards.
Source code in src/orlab/parallel.py
615 616 617 618 619 620 621 | |
Dispersion listeners¶
Canned dispersion listeners.
Both listeners hold only plain-Python/numpy state, so they pickle across
:class:~orlab.SimulationPool's process boundary and survive OpenRocket's
listener cloning. The clone semantics matter for extenders: OpenRocket runs
a copy of your listener, so instance attributes mutated inside hooks are
invisible to the caller afterwards — these two are read-only by design;
subclasses must not accumulate results on self (share a list instead,
as the listeners guide shows).
WindProfile
¶
Bases: AbstractSimulationListener
Deterministic altitude-dependent wind, replacing OpenRocket's wind model including its turbulence — the cross-version mechanism for layered-wind studies (the only native alternative is 24.12-only).
altitudes_m must be strictly increasing; speeds_ms are wind
speeds at those altitudes; directions_rad (scalar or per-point) is
the direction the wind blows from, matching
setWindDirection (0 = from north, π/2 = from east — verified: both
produce identical drift). Between points, the wind vector is
interpolated component-wise (no 359°→1° wraparound artifacts; under
strong direction shear the interpolated magnitude dips below the
endpoint speeds — inherent to vector interpolation). Outside the range,
the end values hold. A sharp layer needs an epsilon step:
altitudes_m=[0, 20, 20.001, 30].
Source code in src/orlab/listeners.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
ThrustFactor
¶
Bases: AbstractSimulationListener
Multiplies every thrust sample by a constant factor — the classic motor-variation dispersion knob (thrust curves vary batch to batch).
Source code in src/orlab/listeners.py
85 86 87 88 89 90 91 92 93 94 95 96 97 | |
Errors¶
orlab exception types.
OrlabError
¶
Bases: Exception
Base class for all orlab errors.
Source code in src/orlab/errors.py
18 19 | |
JarVerificationError
¶
Bases: OrlabError
A jar's sha256 could not be verified (no pin, or a digest mismatch).
Source code in src/orlab/errors.py
22 23 | |
NotAnOpenRocketJar
¶
Bases: OrlabError
The jar path does not point to a readable OpenRocket jar.
Source code in src/orlab/errors.py
26 27 | |
UnsupportedFlightDataType
¶
Bases: OrlabError
A FlightDataType constant does not exist in the loaded OpenRocket version.
Source code in src/orlab/errors.py
30 31 | |
UnsupportedOpenRocketVersion
¶
Bases: OrlabError
The OpenRocket jar's version is older than any known profile.
Source code in src/orlab/errors.py
34 35 | |
StudyAborted
¶
Bases: OrlabError
A SimulationPool study ended early. reason is one of
interrupt, worker-crash, worker-init, task-error;
partial holds every result collected before the abort.
Source code in src/orlab/errors.py
38 39 40 41 42 43 44 45 46 47 48 49 50 | |