Skip to content

Interface: 3D view of the rotor, shaft discretization and probes on the model - #1429

Open
leonardocabr wants to merge 29 commits into
petrobras:mainfrom
leonardocabr:interface-3d
Open

leonardocabr wants to merge 29 commits into
petrobras:mainfrom
leonardocabr:interface-3d

Conversation

@leonardocabr

Copy link
Copy Markdown
Collaborator

Interface: 3D view of the rotor, shaft discretization and probes on the model

Follow-up to #1419. This branch is 29 commits on top of main (3a258dc8), one
of them a merge of main. It touches two places, and they are separable if
you would rather review them apart:

  • ROSS itself, 4 files, +542: Rotor.refine_mesh, Rotor.refine_mesh_by_convergence
    and MultiRotor.refine_mesh, with their tests (ross/rotor_assembly.py,
    ross/multi_rotor/multi_rotor.py, ross/tests/). Nothing existing changes
    behaviour.
  • ross/interface/, 109 files: +18 632 / −358 of our own, of which 9 873 are
    tests, plus three.js r186 vendored under frontend/vendor/three/ (MIT,
    licence included, 82 483 lines). It is vendored rather than loaded from a CDN
    because the packaged executable runs offline, as the other vendored
    libraries do. It is loaded with import() only the first time the 3D view
    is opened.

ROSS: discretizing the shafts

Rotor.refine_mesh(max_ld=0.5, min_ld=0.1, parts=None):

  • The rule: subdivides every shaft element whose length is more than
    max_ld times its diameter, the rule API RP 684 §1.5.2.1 gives for the
    element length: L/D at most 1.0, with 0.5 preferred.
  • How: goes through add_nodes, so every element on a node keeps its place.
  • Layered spans: cut together, by their largest diameter.
  • Couplings: a span holding a CouplingElement is left whole.
  • Short elements: an element shorter than min_ld diameters (0.1) is
    reported with a warning, because cutting cannot fix it.
  • parts: cuts every element into equal parts instead.
  • Example: rotor_example() goes from 6 to 60 elements.

Rotor.refine_mesh_by_convergence(n_modes=6, rtol=1e-3, speed=0, ...):

  • The meshes it compares: the rotor as it is, then L/D 2.0, 1.0, 0.5,
    0.25 and 0.125. Meshes with the same element count are skipped.
  • How it compares: the lowest n_modes natural frequencies of each mesh
    against the next, finer one.
  • What it returns: the coarsest mesh whose frequencies the next refinement
    no longer changes by more than rtol. If none converges, it warns and
    returns the finest.
  • The results: come back as a ConvergenceResults, the class
    Rotor.convergence already uses.
  • Why coarse to fine: comparing every mesh against a fine reference cost
    37 s on a 300-element rotor; this order needs one modal analysis per mesh
    tried.

MultiRotor.refine_mesh refines both rotors and rebuilds the MultiRotor.

Interface

3D view of the rotor.

  • What it draws: the rotor in 3D beside ROSS's 2D figure, drawn from a
    scene the build returns (domain/rotor_scene.py: node positions, diameters
    and colours read from the rotor ROSS built).
  • Equivalent disks: a disk ROSS knows only by its mass and inertia is
    drawn as the equivalent steel disk, and says so.
  • On demand: a frame is drawn only when something changes.
  • Interaction: pan, a legend that hides categories, the axis triad and
    the page's theme.
  • Bench: an optional test bench with a motor under the rotor.
  • Editing: from the view through the list's own paths, and a right-button
    menu: split here, split, discretize, edit, copy, hide, add at node, delete.
  • Measuring: node numbers and dimensions (total length and the spans
    between bearings), and a measuring tape whose ends are dragged along the
    shaft line and stop at the nodes.
  • Shapes: a bank of shapes per category (impellers, seal types, helical
    gears, ...) is only a picture, kept with the element and never sent to ROSS.
    A disk or gear can also be described by its dimensions,
    DiskElement.from_geometry and GearElement.from_geometry.

Modelling.

  • Discretizing the shafts from the list or the 3D view, three ways: by
    L/D (API RP 684), in a number of parts, or by the convergence of the natural
    frequencies. These are the ROSS methods above.
  • Filtering the element list by material, model, nodes, tag or a field's
    value, compared in one unit by the server.
  • The element form opens in a floating window.

Probes on the model.

  • A probe category on the modelling screen. A probe is not part of the
    rotor, since Rotor takes none. The builder checks each one with rs.Probe
    and against the rotor's nodes, because a probe on a node the rotor does not
    have is accepted by ROSS and then reads nothing.
  • Renumbering: a probe is renumbered with its node when a shaft is split,
    discretized or concatenated.
  • Drawing: it is drawn in 3D at its angle.
  • In the analyses: a row of a probe table can name a probe of the model
    instead of typing a node and an angle. The row is filled in from the model on
    every run, so a probe moved by a split shaft is still the one read.
  • Names: the probe's name reaches the chart's legend through tag.
  • MultiRotor: a probe of the driven rotor is numbered as MultiRotor
    numbers that rotor.
  • Frequency response: the output can be such a probe. A radial probe at θ
    reads cos θ·H_x + sin θ·H_y of its node, which is exact because the system
    is linear, and an axial one reads z. The exported Python script carries the
    same function, held to the same numbers by a test.

Verification

  • python check.py: ruff, pytest and the 38 node batteries, 0 of 41
    failed
    . Windows, Python 3.12.6, this repository's ROSS (3.1.0.dev0).
  • ROSS lint: ruff check ross and ruff format --check ross are clean.
  • ROSS tests: the new tests in ross/tests/ pass, and so do the doctests
    of the new methods.
  • The 3D view's geometry is checked in node against scenes ROSS builds. A
    test keeps those stored scenes equal to what the current ROSS builds, so
    they cannot drift.

Found in ROSS along the way

  • FrequencyResponseResults has no probe=. Unlike the unbalance
    response, its plots take a degree of freedom as the output. The interface
    projects the response itself (above). I would like to propose probe= there
    in a separate PR, using the same ru·cos + rv·sin projection as
    calculate_amplitude.
  • An axial probe is skipped without a warning. The probe plots
    continue past an axial probe when number_dof != 6, so on a 4-dof rotor
    it is dropped in silence.

…ad, follow the theme, and redraw the shadow only when it changes
…honeycomb seals, helical gear and a motor on the bench
…sy state, a computing card, WebGL context restore; bearing housings tangent to their base
… or by the convergence of the natural frequencies
…with rs.Probe, renumbered with its node and drawn in 3D
…om the model on every run, named in the legend
@codecov-commenter

codecov-commenter commented Oct 4, 2026 •

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 98.86968% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.65%. Comparing base (4aa371d) to head (41a590b).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
ross/interface/domain/meshing.py 96.79% 5 Missing ⚠️
ross/interface/domain/schema.py 85.71% 4 Missing ⚠️
ross/rotor_assembly.py 96.20% 3 Missing ⚠️
ross/interface/api/schema.py 93.33% 1 Missing ⚠️
ross/interface/domain/probe_refs.py 97.87% 1 Missing ⚠️
ross/interface/domain/rotor_builder.py 98.82% 1 Missing ⚠️
ross/interface/tests/test_freq_response_probes.py 98.79% 1 Missing ⚠️
ross/interface/tests/test_units.py 96.42% 1 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1429      +/-   ##
==========================================
+ Coverage   82.59%   83.65%   +1.06%     
==========================================
  Files         173      181       +8     
  Lines       27549    28977    +1428     
==========================================
+ Hits        22754    24242    +1488     
+ Misses       4795     4735      -60     
Files with missing lines Coverage Δ
ross/interface/api/export.py 90.90% <100.00%> (+5.19%) ⬆️
ross/interface/api/rotor.py 88.57% <100.00%> (+4.89%) ⬆️
ross/interface/domain/concatenation.py 95.62% <ø> (ø)
ross/interface/domain/conversion.py 90.32% <100.00%> (+11.75%) ⬆️
ross/interface/domain/element_registry.py 96.42% <100.00%> (+4.76%) ⬆️
ross/interface/domain/field_catalog.py 100.00% <ø> (ø)
ross/interface/domain/material_names.py 96.96% <ø> (ø)
ross/interface/domain/python_export.py 98.33% <100.00%> (+0.11%) ⬆️
ross/interface/domain/requests.py 100.00% <100.00%> (ø)
ross/interface/domain/ross_import.py 90.62% <ø> (ø)
... and 29 more

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3a258dc...41a590b. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gsabinoo
gsabinoo self-requested a review October 5, 2026 13:49

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants