Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c919c2c
Add actuator dynamics in TVC and ThrottleControl
chichunwang May 5, 2026
1cf76b8
Refactor actuator_tau parameters to use None as default in TVC and Th…
chichunwang May 5, 2026
cb78b68
Add actuator dynamics to RollControl
chichunwang May 30, 2026
bbc5cd3
Move actuators to a new actuator folder and rename actuator classes
zuorenchen Jun 6, 2026
3656f7e
Refactor roll, throttle, and thrust vector acutator with a new actuat…
zuorenchen Jun 6, 2026
233666b
Add pytest for all actuators
zuorenchen Jun 6, 2026
9892e50
Update rocket.py and flight.py for actuator class update
zuorenchen Jun 6, 2026
f13f92a
Fix actuator class calls
zuorenchen Jun 6, 2026
32bf679
Update active control example with new actuator class
zuorenchen Jun 6, 2026
53e588d
Update time_overshoot in flight.py to align rocketpy commit #45a89
zuorenchen Jun 7, 2026
879a921
Fix actuator unit tests
zuorenchen Jun 14, 2026
a26cd8c
Enhance ThrustVectorActuator2D with serialization methods and improve…
zuorenchen Jun 14, 2026
b3187ed
Fix comment msg
zuorenchen Jun 14, 2026
ee0dcf0
Fix pylint unused parameters
zuorenchen Jun 14, 2026
9f0a956
Remove unused import
zuorenchen Jun 14, 2026
29841c2
Fix pylint warnings
zuorenchen Jun 14, 2026
837e0f4
Refactor __run_in_serial() to fix pylint too much statement warning
zuorenchen Jun 14, 2026
02ba66e
Fix: use warning instead of printf
zuorenchen Jun 14, 2026
8281a6a
Fix comment
zuorenchen Jun 14, 2026
0ec4556
Fix: use warning instead of printf
zuorenchen Jun 14, 2026
4398e40
Run ruff format
zuorenchen Jun 14, 2026
13f53f0
Fix thrust3 and effective_thrust name
zuorenchen Jun 14, 2026
9fa47f5
Fix pytests
zuorenchen Jun 14, 2026
647ed91
Fix pytest utilities
zuorenchen Jun 14, 2026
e914ec0
Fix integration/gnss pytest
zuorenchen Jun 14, 2026
1d48998
Update readme
zuorenchen Jun 25, 2026
7d1843a
Merge pull request #8 from ARRC-Rocket/enh/actuator
chichunwang Jun 26, 2026
a6dda6a
Merge pull request #9 from ARRC-Rocket/enh/fix_pytest
chichunwang Jun 26, 2026
e9ebff6
ENH: seed sensor measurement noise per instance (#13)
thc1006 Jun 27, 2026
e06285b
TST: seed the noisy accelerometer and gyroscope fixtures (#14)
thc1006 Jun 27, 2026
36381dc
ENH: pull v1.13 from RocketPy (#16)
zuorenchen Jul 26, 2026
bfcd57b
test: characterization tests for Flight.step_simulation() (#11)
thc1006 Jul 26, 2026
2762df1
Merge branch 'master' into develop
zuorenchen Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .agents/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# RocketPy Workspace Instructions

## Code Style
- Use snake_case for variables, functions, methods, and modules. Use descriptive names.
- Use PascalCase for classes and UPPER_SNAKE_CASE for constants.
- Keep lines at 88 characters and follow PEP 8 unless existing code in the target file differs.
- Run Ruff as the source of truth for formatting/import organization:
- `make format`
- `make lint`
- Use NumPy-style docstrings for public classes, methods, and functions, including units.
- In case of tooling drift between docs and config, prefer current repository tooling in `Makefile`
and `pyproject.toml`.

## Architecture
- RocketPy is a modular Python library; keep feature logic in the correct package boundary:
- `rocketpy/simulation`: flight simulation and Monte Carlo orchestration.
- `rocketpy/rocket`, `rocketpy/motors`, `rocketpy/environment`: domain models.
- `rocketpy/mathutils`: numerical primitives and interpolation utilities.
- `rocketpy/plots`, `rocketpy/prints`: output and visualization layers.
- Prefer extending existing classes/patterns over introducing new top-level abstractions.
- Preserve public API stability in `rocketpy/__init__.py` exports.

## Build and Test
- Use Makefile targets for OS-agnostic workflows:
- `make install`
- `make pytest`
- `make pytest-slow`
- `make coverage`
- `make coverage-report`
- `make build-docs`
- Before finishing code changes, run focused tests first, then broader relevant suites.
- When running Python directly in this workspace, prefer the project virtual
environment interpreter: `.venv/bin/python` on Unix/macOS or
`.venv/Scripts/python.exe` on Windows.
- Slow tests are explicitly marked with `@pytest.mark.slow` and are run with `make pytest-slow`.
- For docs changes, check `make build-docs` output and resolve warnings/errors when practical.

## Development Workflow
- Target pull requests to `develop` by default; `master` is the stable branch.
- Use branch names in `type/description` format, such as:
- `bug/<description>`
- `doc/<description>`
- `enh/<description>`
- `mnt/<description>`
- `tst/<description>`
- Prefer rebasing feature branches on top of `develop` to keep history linear.
- Keep commit and PR titles explicit and prefixed with project acronyms when possible:
- `BUG`, `DOC`, `ENH`, `MNT`, `TST`, `BLD`, `REL`, `REV`, `STY`, `DEV`.

## Conventions
- SI units are the default. Document units and coordinate-system references explicitly.
- Position/reference-frame arguments are critical in this codebase. Be explicit about orientation
(for example, `tail_to_nose`, `nozzle_to_combustion_chamber`).
- Include unit tests for new behavior. Follow AAA structure and clear test names.
- Use fixtures from `tests/fixtures`; if adding a new fixture module, update `tests/conftest.py`.
- Use `pytest.approx` for floating-point checks where appropriate.
- Use `@cached_property` for expensive computations when helpful, and be careful with stale-cache
behavior when underlying mutable state changes.
- Keep behavior backward compatible across the public API exported via `rocketpy/__init__.py`.
- Prefer extending existing module patterns over creating new top-level package structure.

## Testing Taxonomy
- Unit tests are mandatory for new behavior.
- Unit tests in RocketPy can be sociable (real collaborators allowed) but should still be fast and
method-focused.
- Treat tests as integration tests when they are strongly I/O-oriented or broad across many methods,
including `all_info()` convention cases.
- Acceptance tests represent realistic user/flight scenarios and may compare simulation thresholds to
known flight data.

## Documentation Links
- Contributor workflow and setup: `docs/development/setting_up.rst`
- Style and naming details: `docs/development/style_guide.rst`
- Testing philosophy and structure: `docs/development/testing.rst`
- API reference conventions: `docs/reference/index.rst`
- Domain/physics background: `docs/technical/index.rst`

## Scoped Customizations
- Simulation-specific rules: `.agents/skills/simulation-safety/SKILL.md`
- Test-authoring rules: `.agents/skills/tests-python/SKILL.md`
- RST/Sphinx documentation rules: `.agents/skills/sphinx-docs/SKILL.md`
- Specialized review persona: `.agents/skills/rocketpy-reviewer/SKILL.md`
62 changes: 62 additions & 0 deletions .agents/skills/rocketpy-reviewer/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
description: "Physics-safe RocketPy code review agent. Use for pull request review, unit consistency checks, coordinate-frame validation, cached-property risk detection, and regression-focused test-gap analysis."
name: "RocketPy Reviewer"
tools: [read, search]
argument-hint: "Review these changes for physics correctness and regression risk: <scope or files>"
user-invocable: true
---
You are a RocketPy-focused reviewer for physics safety and regression risk.

## Goals

- Detect behavioral regressions and numerical/physics risks before merge.
- Validate unit consistency and coordinate/reference-frame correctness.
- Identify stale-cache risks when `@cached_property` interacts with mutable state.
- Check test coverage quality for changed behavior.
- Verify alignment with RocketPy workflow and contributor conventions.

## Review Priorities

1. Correctness and safety issues (highest severity).
2. Behavioral regressions and API compatibility.
3. Numerical stability and tolerance correctness.
4. Missing tests or weak assertions.
5. Documentation mismatches affecting users.
6. Workflow violations (test placement, branch/PR conventions, or missing validation evidence).

## RocketPy-Specific Checks

- SI units are explicit and consistent.
- Orientation conventions are unambiguous (`tail_to_nose`, `nozzle_to_combustion_chamber`, etc.).
- New/changed simulation logic does not silently invalidate cached values.
- Floating-point assertions use `pytest.approx` where needed.
- New fixtures are wired through `tests/conftest.py` when applicable.
- Test type is appropriate for scope (`unit`, `integration`, `acceptance`) and `all_info()`-style tests
are not misclassified.
- New behavior includes at least one regression-oriented test and relevant edge-case checks.
- For docs-affecting changes, references and paths remain valid and build warnings are addressed.
- Tooling recommendations match current repository setup (prefer Makefile plus `pyproject.toml`
settings when docs are outdated).

## Validation Expectations

- Prefer focused test runs first, then broader relevant suites.
- Recommend `make format` and `make lint` when style/lint risks are present.
- Recommend `make build-docs` when `.rst` files or API docs are changed.

## Output Format

Provide findings first, ordered by severity.
For each finding include:
- Severity: Critical, High, Medium, or Low
- Location: file path and line
- Why it matters: behavioral or physics risk
- Suggested fix: concrete, minimal change

After findings, include:
- Open questions or assumptions
- Residual risks or testing gaps
- Brief change summary
- Suggested validation commands (only when useful)

If no findings are identified, state that explicitly and still report residual risks/testing gaps.
41 changes: 41 additions & 0 deletions .agents/skills/simulation-safety/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
description: "Use when editing rocketpy/simulation code, including Flight state updates, Monte Carlo orchestration, post-processing, or cached computations. Covers simulation state safety, unit/reference-frame clarity, and regression checks."
name: "Simulation Safety"
applyTo: "rocketpy/simulation/**/*.py"
---
# Simulation Safety Guidelines

- Keep simulation logic inside `rocketpy/simulation` and avoid leaking domain behavior that belongs in
`rocketpy/rocket`, `rocketpy/motors`, or `rocketpy/environment`.
- Preserve public API behavior and exported names used by `rocketpy/__init__.py`.
- Prefer extending existing simulation components before creating new abstractions:
- `flight.py`: simulation state, integration flow, and post-processing.
- `monte_carlo.py`: orchestration and statistical execution workflows.
- `flight_data_exporter.py` and `flight_data_importer.py`: persistence and interchange.
- `flight_comparator.py`: comparative analysis outputs.
- Be explicit with physical units and reference frames in new parameters, attributes, and docstrings.
- For position/orientation-sensitive behavior, use explicit conventions (for example
`tail_to_nose`, `nozzle_to_combustion_chamber`) and avoid implicit assumptions.
- Treat state mutation carefully when cached values exist.
- If changes can invalidate `@cached_property` values, either avoid post-computation mutation or
explicitly invalidate affected caches in a controlled, documented way.
- Keep numerical behavior deterministic unless stochastic behavior is intentional and documented.
- For Monte Carlo and stochastic code paths, make randomness controllable and reproducible when tests
rely on it.
- Prefer vectorized NumPy operations for hot paths and avoid introducing Python loops in
performance-critical sections without justification.
- Guard against numerical edge cases (zero/near-zero denominators, interpolation limits, and boundary
conditions).
- Do not change default numerical tolerances or integration behavior without documenting motivation and
validating regression impact.
- Add focused regression tests for changed behavior, including edge cases and orientation-dependent
behavior.
- For floating-point expectations, use `pytest.approx` with meaningful tolerances.
- Run focused tests first, then broader relevant tests (`make pytest` and `make pytest-slow` when
applicable).

See:
- `docs/development/testing.rst`
- `docs/development/style_guide.rst`
- `docs/development/setting_up.rst`
- `docs/technical/index.rst`
32 changes: 32 additions & 0 deletions .agents/skills/sphinx-docs/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
description: "Use when writing or editing docs/**/*.rst. Covers Sphinx/reStructuredText conventions, cross-references, toctree hygiene, and RocketPy unit/reference-frame documentation requirements."
name: "Sphinx RST Conventions"
applyTo: "docs/**/*.rst"
---
# Sphinx and RST Guidelines

- Follow existing heading hierarchy and style in the target document.
- Prefer linking to existing documentation pages instead of duplicating content.
- Use Sphinx cross-references where appropriate (`:class:`, `:func:`, `:mod:`, `:doc:`, `:ref:`).
- Keep API names and module paths consistent with current code exports.
- Document physical units and coordinate/reference-frame conventions explicitly.
- Include concise, practical examples when introducing new user-facing behavior.
- Keep prose clear and technical; avoid marketing language in development/reference docs.
- When adding a new page, update the relevant `toctree` so it appears in navigation.
- Use RocketPy docs build workflow:
- `make build-docs` from repository root for normal validation.
- If stale artifacts appear, clean docs build outputs via `cd docs && make clean`, then rebuild.
- Treat new Sphinx warnings/errors as issues to fix or explicitly call out in review notes.
- Keep `docs/index.rst` section structure coherent with user, development, reference, technical, and
examples navigation.
- Do not edit Sphinx-generated scaffolding files unless explicitly requested:
- `docs/Makefile`
- `docs/make.bat`
- For API docs, ensure references remain aligned with exported/public objects and current module paths.

See:
- `docs/index.rst`
- `docs/development/build_docs.rst`
- `docs/development/style_guide.rst`
- `docs/reference/index.rst`
- `docs/technical/index.rst`
36 changes: 36 additions & 0 deletions .agents/skills/tests-python/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
description: "Use when creating or editing pytest files in tests/. Enforces AAA structure, naming conventions, fixture usage, parameterization, slow-test marking, and numerical assertion practices for RocketPy."
name: "RocketPy Pytest Standards"
applyTo: "tests/**/*.py"
---
# RocketPy Test Authoring Guidelines

- Unit tests are mandatory for new behavior.
- Follow AAA structure in each test: Arrange, Act, Assert.
- Use descriptive test names matching project convention:
- `test_methodname`
- `test_methodname_stateundertest`
- `test_methodname_expectedbehaviour`
- Include docstrings that clearly state expected behavior and context.
- Prefer parameterization for scenario matrices instead of duplicated tests.
- Classify tests correctly:
- `tests/unit`: fast, method-focused tests (sociable unit tests are acceptable in RocketPy).
- `tests/integration`: broad multi-method/component interactions and strongly I/O-oriented cases.
- `tests/acceptance`: realistic end-user/flight scenarios with threshold-based expectations.
- By RocketPy convention, tests centered on `all_info()` behavior are integration tests.
- Reuse fixtures from `tests/fixtures` whenever possible.
- Keep fixture organization aligned with existing categories under `tests/fixtures`
(environment, flight, motor, rockets, surfaces, units, etc.).
- If you add a new fixture module, update `tests/conftest.py` so fixtures are discoverable.
- Keep tests deterministic: set seeds when randomness is involved and avoid unstable external
dependencies unless integration behavior explicitly requires them.
- Use `pytest.approx` for floating-point comparisons with realistic tolerances.
- Mark expensive tests with `@pytest.mark.slow` and ensure they can run under the project slow-test
workflow.
- Include at least one negative or edge-case assertion for new behaviors.
- When adding a bug fix, include a regression test that fails before the fix and passes after it.

See:
- `docs/development/testing.rst`
- `docs/development/style_guide.rst`
- `docs/development/setting_up.rst`
40 changes: 40 additions & 0 deletions .claude/hooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Claude Code hooks

Project-level [Claude Code hooks](https://docs.claude.com/en/docs/claude-code/hooks)
that keep Claude's edits lint-clean and stop lint failures from reaching CI. They
are wired up in [`.claude/settings.json`](../settings.json) and run automatically
for anyone using Claude Code in this repo.

Both hooks only run **ruff** (the fast linter/formatter, ~0.15s for the whole
repo). Pylint is intentionally left to CI: on this codebase its per-file startup
cost is seconds, too slow for an interactive guard. ruff is also what has actually
been breaking the `Linters` job.

## Hooks

| Hook | Event | What it does |
| --- | --- | --- |
| [`ruff_on_edit.py`](ruff_on_edit.py) | `PostToolUse` on `Edit`/`Write`/`MultiEdit` | After Claude edits a `.py` file, runs `ruff format` then `ruff check --fix` on that one file. Surfaces any unfixable lint issues back to Claude. |
| [`ruff_guard_push.py`](ruff_guard_push.py) | `PreToolUse` on `Bash` | Before a `git push`, runs `ruff check` + `ruff format --check` over the repo and **blocks the push** if either would fail (i.e. before it turns CI red). |

## Design guarantees

- **Cross-platform** (Windows / macOS / Linux): pure Python, no shell built-ins,
no OS-specific paths. ruff is invoked as `<current python> -m ruff` so it
resolves to the same environment the hook runs in.
- **Never gets in the way**: if `ruff` is not installed, both hooks are a silent
no-op. The push guard only acts on actual `git push` commands.

## Requirements

A working `python` on `PATH` (an activated virtualenv is the normal setup) with
`ruff` installed: `pip install ruff` — already included in `pip install .[tests]`.

## Testing a hook manually

Pipe a sample event payload to a hook on stdin:

```bash
printf '{"tool_input":{"file_path":"some_file.py"}}' | python .claude/hooks/ruff_on_edit.py
printf '{"tool_input":{"command":"git push"}}' | python .claude/hooks/ruff_guard_push.py
```
78 changes: 78 additions & 0 deletions .claude/hooks/ruff_guard_push.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""Claude Code ``PreToolUse`` hook: block ``git push`` if ruff would fail in CI.

Runs before every ``Bash`` command. If the command is a ``git push``, it runs the
two fast ruff steps from the Linters CI job (``ruff check .`` and
``ruff format --check .``) over the repo. If either would fail, the push is
blocked (exit code 2) and the failure is reported back to Claude so it gets fixed
*before* it turns the CI red.

Only ruff runs here (both steps together are ~0.15s). Pylint is intentionally left
to CI: on this repo pylint costs seconds-per-file of startup, which is too slow for
an interactive guard. ruff is what has actually been breaking the Linters job.

Design notes
------------
* ruff is invoked as ``<current python> -m ruff`` (see ``ruff_on_edit.py``).
* Cross-platform: pure Python, no shell built-ins, no OS-specific paths.
* Silent no-op when the command is not a push, or when ruff is not installed.
"""

import importlib.util
import json
import os
import re
import subprocess
import sys

# Match ``git push`` as a real command (start of line or after a shell
# separator), tolerating global flags like ``git -C . push``. Avoids most
# false positives from the substring "push" appearing elsewhere.
_GIT_PUSH = re.compile(r"(?:^|[\s;&|(`])git(?:\s+-\S+|\s+--\S+)*\s+push\b")


def main() -> int:
try:
payload = json.load(sys.stdin)
except (json.JSONDecodeError, ValueError):
return 0

command = (payload.get("tool_input") or {}).get("command", "")
if not isinstance(command, str) or not _GIT_PUSH.search(command):
return 0

if importlib.util.find_spec("ruff") is None:
return 0 # ruff not installed: don't block pushes.

# Target the project root explicitly. ``CLAUDE_PROJECT_DIR`` is set by Claude
# Code to the native-format project root; passing it as a path argument (not
# as the subprocess ``cwd``) keeps this robust across platforms/shells. Falls
# back to ".", which resolves against the hook's working directory.
target = os.environ.get("CLAUDE_PROJECT_DIR") or "."
ruff = [sys.executable, "-m", "ruff"]
check = subprocess.run(ruff + ["check", target], capture_output=True, text=True)
fmt = subprocess.run(
ruff + ["format", "--check", target], capture_output=True, text=True
)
if check.returncode == 0 and fmt.returncode == 0:
return 0

out = [
"[ruff] Push blocked — this would fail the Linters CI job. "
"Fix the issues below, then push again.\n"
]
if check.returncode != 0:
out.append("--- ruff check ---\n" + (check.stdout or "") + (check.stderr or ""))
if fmt.returncode != 0:
out.append(
"--- ruff format --check . ---\n"
+ (fmt.stdout or "")
+ (fmt.stderr or "")
+ "\nFix formatting with: python -m ruff format .\n"
)
sys.stderr.write("\n".join(out))
return 2


if __name__ == "__main__":
raise SystemExit(main())
Loading
Loading