Tutorial about Seals: Labyrinth, Hole-pattern, and Hybrid#

This tutorial explains how to use three seal models in ROSS (ross/seals/):

  • LabyrinthSeal — multi-tooth compressible throttling seal.

  • HolePatternSeal — bulk-flow model for annular seals with hole / honeycomb–type cells (pocket damper seals).

  • HybridSeal — combined hole-pattern + labyrinth with iterative mass-flow matching at the interface.

ROSS units are SI internally. Use ross.units.Q_ for convenient input (for example RPM → rad/s).

1. Labyrinth seal (LabyrinthSeal)#

A labyrinth restricts leakage through a series of throttlings (teeth). ROSS solves compressible flow along the seal, estimates mass flow (including choke where relevant), swirl in cavities, and perturbed equations for stiffness and damping (and optional fluid-related mass terms) versus whirl speed.

Typical inputs: shaft radius, radial clearance, number of teeth, pitch and tooth geometry, seal type ("rotor", "stator", or "inter"), pressures, temperature, shaft frequency(ies), preswirl, and gas data.

# Make sure the default renderer is set to 'notebook' for inline plots in Jupyter
import plotly.io as pio
pio.renderers.default = "notebook"
from ross.seals.labyrinth_seal import LabyrinthSeal
from ross.units import Q_

seal = LabyrinthSeal(
    n=0,
    shaft_radius=Q_(72.5, "mm"),
    radial_clearance=Q_(0.3, "mm"),
    n_teeth=16,
    pitch=Q_(3.175, "mm"),
    tooth_height=Q_(3.175, "mm"),
    tooth_width=Q_(0.1524, "mm"),
    seal_type="inter",
    inlet_pressure=308_000.0,
    outlet_pressure=94_300.0,
    inlet_temperature=283.15,
    frequency=Q_([5000, 8000, 11000], "RPM"),
    preswirl=0.98,
    gas_composition={"Nitrogen": 0.79, "Oxygen": 0.21},
)
seal
c:\Users\vinic\OneDrive\Desktop\Digital_Twin\Github\ross\venv\Lib\site-packages\tqdm\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
LabyrinthSeal(n=0, n_link=None,
 kxx=[-1.94449649e+04 -3.15819258e+09  2.80261312e+15], kxy=[ 1.65479279e+04 -7.83714166e+09  9.36204948e+15],
 kyx=[-1.65479279e+04  7.83714166e+09 -9.36204948e+15], kyy=[-1.94449649e+04 -3.15819258e+09  2.80261312e+15],
 kzz=[0, 0, 0], cxx=[ 1.46954145e+01 -1.03899648e+07  7.99109118e+12],
 cxy=[ 3.54252215e+01  2.60730549e+06 -2.55043342e+12], cyx=[-3.54252215e+01 -2.60730549e+06  2.55043342e+12],
 cyy=[ 1.46954145e+01 -1.03899648e+07  7.99109118e+12], czz=[0, 0, 0],
 mxx=[0, 0, 0], mxy=[0, 0, 0],
 myx=[0, 0, 0], myy=[0, 0, 0],
 mzz=[0, 0, 0],
 frequency=[ 523.5987756   837.75804096 1151.91730632], tag=None)

Access: Coefficients are stored as lists aligned with frequency (for example seal.kxx, seal.kxy, …; seal.cxx, …). Leakage: seal.seal_leakage.

Without gas_composition, you must supply molar, gamma, tz (two temperatures [K]), and muz (two dynamic viscosities [Pa·s]).

2. Hole-pattern seal (HolePatternSeal)#

Hole-pattern (including honeycomb stator) seals are represented by a one-dimensional bulk-flow model along the seal length: base compressible flow, perturbation for dynamic coefficients, integrated direct and cross stiffness, damping, and apparent mass terms.

Geometrically the model uses a representative cell (cell_length, cell_width, cell_depth) and roughness (dimensionless E/D), not a full CAD mesh.

from ross.seals.holepattern_seal import HolePatternSeal
from ross.units import Q_

# Geometry derived from honeycomb_data.pdf (see table above)
DRUM_OD_M = 196.5e-3
shaft_radius = DRUM_OD_M / 2
length_honeycomb = 84.9e-3
diametral_clearance = 0.36e-3
radial_clearance = diametral_clearance / 2

holepattern = HolePatternSeal(
    n=0,
    shaft_radius=shaft_radius,
    radial_clearance=radial_clearance,
    length=length_honeycomb,
    roughness=1.0e-4,
    cell_length=length_honeycomb / 37,
    cell_width=2.1e-3,
    cell_depth=2.8e-3,
    inlet_pressure=1_830_000.0,
    outlet_pressure=823_500.0,
    inlet_temperature=300.0,
    frequency=Q_([5000], "RPM"),
    gas_composition={
        "Nitrogen": 0.7812,
        "Oxygen": 0.2096,
        "Argon": 0.0092,
    },
    preswirl=1.0,
    entr_coef=0.1,
    exit_coef=0.5,
    nz=40,
)
holepattern
HolePatternSeal(n=0, n_link=None,
 kxx=[5760043.48572718], kxy=[1377442.42449097],
 kyx=[-1377442.42449097], kyy=[5760043.48572718],
 kzz=[0], cxx=[2470.55767601],
 cxy=[-477.40987914], cyx=[477.40987914],
 cyy=[2470.55767601], czz=[0],
 mxx=[-0.4221625], mxy=[0.11170356],
 myx=[-0.11170356], myy=[-0.4221625],
 mzz=[0],
 frequency=[523.5987756], tag=None)

3. Hybrid seal (HybridSeal)#

HybridSeal stacks the two models in series along the pressure path:

  1. HolePatternSeal from global inlet_pressure down to an unknown interface pressure

  2. LabyrinthSeal from that interface to global outlet_pressure

ROSS finds the interface pressure by bisection so that the mass flow leaving the hole-pattern stage matches the mass flow leaving the labyrinth (leakage continuity). The resulting rotordynamic coefficients are added (series force contribution from both components), consistent with the implementation in hybrid_seal.py.

3.1 Concept#

After solving for the interface pressure, the hybrid element exposes:

  • hybrid.interface_pressure — converged junction pressure [Pa]

  • hybrid.n_iterations — bisection steps

  • hybrid.hole_pattern and hybrid.laby — underlying HolePatternSeal and LabyrinthSeal instances

  • hybrid.seal_leakage — aligned leakage

  • hybrid.summary_results() — tabular summary (PrettyTable)

  • hybrid.plot_convergence() — Plotly figure for convergence / pressure / leakage histories

Iterative Pressure Matching#

The model uses a bisection method to find the interface pressure (\(P_{int}\)) between the two seal stages that satisfies mass conservation:

\[\dot{m}_{hole-pattern}(P_{in}, P_{int}) = \dot{m}_{labyrinth}(P_{int}, P_{out})\]

where:

  • \(P_{in}\) is the inlet pressure (upstream of hole-pattern seal)

  • \(P_{out}\) is the outlet pressure (downstream of labyrinth seal)

  • \(\dot{m}\) represents the mass flow rate (leakage)

from ross.seals.hybrid_seal import HybridSeal
from ross.units import Q_

gas_composition = {
    "Nitrogen": 0.7812,
    "Oxygen": 0.2096,
    "Argon": 0.0092,
}

hole_pattern_parameters = {
    "radial_clearance": 0.0003,
    "length": 0.04,
    "roughness": 0.0001,
    "cell_length": 0.003,
    "cell_width": 0.003,
    "cell_depth": 0.002,
    "preswirl": 0.8,
    "entr_coef": 0.5,
    "exit_coef": 1.0,
}

labyrinth_parameters = {
    "radial_clearance": Q_(0.25, "mm"),
    "n_teeth": 10,
    "pitch": Q_(3, "mm"),
    "tooth_height": Q_(3, "mm"),
    "tooth_width": Q_(0.15, "mm"),
    "seal_type": "inter",
    "preswirl": 0.9,
    "tz": [300.0, 299.5],
    "muz": [1.85e-05, 1.84e-05],
}

hybrid = HybridSeal(
    n=0,
    shaft_radius=Q_(25, "mm"),
    inlet_pressure=500_000.0,
    outlet_pressure=100_000.0,
    inlet_temperature=300.0,
    frequency=Q_([2000, 3000, 5000], "RPM"),
    gas_composition=gas_composition,
    hole_pattern_parameters=hole_pattern_parameters,
    labyrinth_parameters=labyrinth_parameters,
)

hybrid.format_table(frequency_units="RPM")
Frequency [RPM] kxx [N/m] kyy [N/m] kxy [N/m] kyx [N/m] kzz [N/m] cxx [N*s/m] cyy [N*s/m] cxy [N*s/m] cyx [N*s/m] czz [N*s/m]
2000.0 203520.12407 203520.12407 11480.74088 -11480.74088 0.0 63.12131 63.12131 -3.01923 3.01923 0.0
2750.0 -604549639.96381 -604549639.96381 -3443320335.47969 3443320335.47969 0.0 -6550598.04353 -6550598.04353 1238528.75563 -1238528.75563 0.0
3500.0 2416438849.994 2416438849.994 13765193232.82072 -13765193232.82072 0.0 26175602.67469 26175602.67469 -4950493.21321 4950493.21321 0.0
4250.0 9063168989.99748 9063168989.99748 51625552185.64214 -51625552185.64214 0.0 98178665.27597 98178665.27597 -18567068.92576 18567068.92576 0.0
5000.0 19335640780.04664 19335640780.04664 110137756522.98457 -110137756522.98457 0.0 209458589.76032 209458589.76032 -39611198.38201 39611198.38201 0.0

4. Plots and Results#

4.1. Coefficient vs frequency plots#

LabyrinthSeal, HolePatternSeal, and HybridSeal inherit SealElementBearingElement.plot(). Pass stiffness names (kxx, kxy, …) or damping names (cxx, …) in one call (they cannot be mixed). The method interpolates between the discrete frequency samples and returns a Plotly figure. The same call works on holepattern or hybrid once those objects exist (use a denser frequency list if you need a smoother curve).

fig_k = seal.plot(
    coefficients=["kxx", "kyy", "kxy", "kyx"],
    frequency_units="RPM",
)
fig_k.update_layout(title="Labyrinth seal — stiffness vs whirl speed")
fig_k.show()

fig_c = seal.plot(
    coefficients=["cxx", "cyy", "cxy", "cyx"],
    frequency_units="RPM",
)
fig_c.update_layout(title="Labyrinth seal — damping vs whirl speed")
fig_c.show()

4.2. plot_pressure_distribution() — axial pressure profile#

Both LabyrinthSeal and HolePatternSeal implement plot_pressure_distribution(pressure_units="MPa", length_units="m", ...), returning a Plotly line plot of pressure vs axial position along the solved 1D domain.

  • LabyrinthSeal: pressure at cavity centres / stages — typically a step-like decay from inlet to outlet.

  • HolePatternSeal: continuous profile along the discretised nz stations — smoother axial pressure drop with frictional and loss behaviour embedded in the base flow.

fig_p = seal.plot_pressure_distribution(pressure_units="MPa", length_units="mm")
fig_p.show()

4.2. HybridSeal—only: convergence diagnostic plots and table#

Method / attribute

Purpose

summary_results()

PrettyTable with iterations, final interface pressure, leakage

plot_convergence()

Three stacked subplots: (1) relative leakage error vs iteration — log-scaled (y), should trend downward; (2) mass-flow rates — hole-pattern vs labyrinth leakages converging to the same value; (3) interface pressure vs iteration — settling to the bisection root

convergence_history, pressure_history, leakage_hole_history, leakage_laby_history

Raw lists for custom plots

# After building hybrid (Section 4)
table = hybrid.summary_results()
print(table)  # ASCII table: Parameter | Value

fig_conv = hybrid.plot_convergence()
fig_conv.show()
+-------------------------+--------------+
| Parameter               |        Value |
+-------------------------+--------------+
| Number of Iterations    |           21 |
| Final Convergence       | 1.017087e-07 |
| Interface Pressure (Pa) |    219426.92 |
| Seal Leakage (kg/s)     | 3.488871e-02 |
+-------------------------+--------------+

5. Practical tips#

  1. Gas model: Prefer gas_composition for real mixtures so that ccp can derive molar, gamma, and Sutherland coefficients for HolePatternSeal (and labyrinth when applicable).

  2. Performance: HolePatternSeal and nested solves in HybridSeal can be heavy; reduce nz while prototyping, then refine.

  3. Validation: Compare trends (leakage vs. pressure drop, stiffness order of magnitude) with vendor curves or test data where available.

  4. Tests as reference: ross/tests/test_labyrinth.py, test_holepattern.py, and test_hybrid_seal.py contain regression values and parameter sets that always run in CI.