turbo_moc.geometry.passage module#
turbo_moc.geometry.passage – single flow-passage (one blade-to-blade channel) extraction, for CFD meshing with periodic boundary conditions.
Domain picture (per direct user sketch, not the “two blade surfaces as the domain’s own boundary” idea tried earlier in this module’s history): a pitch-wide domain – two periodic side walls, one pitch apart, each running VERTICAL from the flat inlet cap down to just short of the leading edge, then following the actual blade-to-blade centerline down to just short of the trailing edge, then VERTICAL again down to the flat outlet cap. Both walls are the exact same bent/curved polyline, one shifted from the other by exactly one pitch (in x for a stator, in y for a rotor), so the inlet and outlet cap lengths are BOTH exactly one pitch regardless of the bends – a pure pitchwise translation preserves horizontal distance at every height, bent or curved path or not (and this is why any future chamfer/fillet on the kinks MUST be applied identically to both walls – e.g. filleting the same vertex index on both, same radius – rather than picked independently, or the two walls stop being exact pitch-translates of each other and periodicity breaks).
The middle (non-vertical) section differs by source:
Stator: a mirrored-wall construction, so the middle section is genuinely two STRAIGHT segments – a line through the leading edge at metal_angle_in, a line through the trailing edge at metal_angle_out, meeting at their own intersection. The wall passes exactly through the blade’s own LE/TE corners, and the throat-height centerline runs exactly through the mid-pitch point at the trailing edge (the exit angle IS the flow direction there).
Rotor: pressure(c) and suction(c)+pitch+translate are literally the two walls design_rotor_vortex_blade’s own _close_blade_le_te closes into ONE blade’s own solid (blade_lower/blade_upper – “translate” is a correction beyond bare +pitch so the TE fillet arc’s radius comes out right, already stored in blade_data[“blade”][“translate”]). Their midpoint is therefore the blade’s own mid-thickness line, NOT the passage. The wall is instead the CENTERLINE that pairs THIS blade’s own outer wall (suction(c)+pitch+translate) with the NEXT blade’s own wall (pressure(c)+pitch, not this blade’s unshifted pressure) – the blade-midline shifted by one FULL pitch, tracked at every chordwise station (not a fixed offset, which is only safe where the local blade thickness is less than the offset – tried and reverted, see git history, it sliced through the thick LE bulb). Computed only where BOTH surfaces have real data (pressure/suction don’t converge near the true LE/TE – they asymptote to PARALLEL lines, pitch apart, never meeting – see turbo_moc.rotor.vortex_blade’s own module docstring), then extended as a STRAIGHT LINE continuing the CENTERLINE’s own last real trend out to the blade’s true LE/TE tip (an earlier version blended each surface toward the tip separately instead – also tried and reverted, it bent the wrong way right at the LE since that assumed a convergence that doesn’t happen). NOTE: the rotor’s raw chordwise convention has max(c_vals) on the OUTLET side, not the inlet (opposite of the stator’s) – see _passage_geometry.
For the stator, both walls sit at +/- half a pitch from the LE/TE reference line, so the blade’s own position runs through the domain’s MIDDLE. For the rotor, wall_ref IS already the true passage centerline, so one wall is that reference as-is and the other is it shifted by one full pitch (0/+pitch, no extra centering needed). Either way, sized and positioned so ONE COMPLETE blade sits fully inside the domain, never clipped by its own edges, then that one blade is subtracted out as an internal hole.
extract_radial_passage_2d conformally maps this SAME domain (via turbo_moc.geometry.radial’s log-spiral wrap, the same mapping already used to wrap blades onto an annulus in Phase 5) onto a passage between two radii – the straight vertical/cap segments become log-spiral arcs under this mapping, not straight lines, so they’re densely sampled first (_dense_boundary_points) rather than passed as bare 2-point segments the way the axial-only wire (extract_axial_passage_2d) can get away with.
Requires cadquery (not a core turbo_moc dependency – import kept local, same convention as turbo_moc.geometry.blade’s STEP export functions).
- turbo_moc.geometry.passage.extract_axial_passage_2d(blade_data, pitch, face_path, solid_path=None, extrude_length=1.0, source='stator', inlet_chords=1.0, outlet_chords=6.0, bend_margin_inlet=0.15, bend_margin_outlet=0.05)[source]#
One periodic passage domain (a pitch-wide domain, vertical near the inlet/outlet and following the blade-to-blade centerline in between, with the blade solid subtracted out as an internal hole) in the unrolled/axial cascade view, as a STEP face and, optionally, an extruded 3D solid. See module docstring for the domain’s shape and why the stator and rotor get different middle-section constructions.
- Parameters:
- blade_datadict
Stator (parametrize_stator_blade/_semi output – needs “blade_curve”/”trailing_edge”/”suction”/”metal_angle_in”/ “metal_angle_out”/”axial_chord_convergent”/ “axial_chord_divergent”) or rotor (design_rotor_vortex_blade output – needs “blade”/”suction”/”pressure”/”chord”) blade dict. Pick which via source.
- pitchfloat
Blade-to-blade pitch (mm), i.e. the periodic translation. For a stator this IS blade_data[“pitch”]; for a rotor that’s been scaled from its own nondimensional r* (see turbo_moc.app’s rotor_scale_mm), pass the SCALED pitch, and pre-scale blade_data’s own length-valued arrays/fields by the same factor (angles need no scaling).
- face_path, solid_pathstr
Output STEP file paths. solid_path is optional – omit to skip the 3D extrusion and only export the 2D face.
- extrude_lengthfloat
3D solid extrusion depth (mm), only used if solid_path is given.
- sourcestr
“stator” or “rotor” – which raw-surface axis convention to use: stator’s pitch runs along x (pitchwise), rotor’s along y (see turbo_moc/geometry/radial.py’s module docstring on the two blades’ opposite chordwise/pitchwise axis conventions).
- inlet_chords, outlet_chordsfloat
How far the inlet/outlet caps sit upstream of the leading edge / downstream of the trailing edge, each as a multiple of the blade’s own chord (stator:
axial_chord_convergent + axial_chord_divergent; rotor: “chord”) – e.g. the outlet default 6.0 places the outlet six chords downstream, far enough that the outlet boundary condition doesn’t interact with the blade’s own near-field. Decoupled from the stator’s own inlet_chords/ outlet_chords – pass whichever value applies to source. NOTE: for the rotor, max(c_vals) (blade’s own raw chordwise convention) is the OUTLET side, not the inlet (opposite of the stator’s), so internally outlet_chords is applied there and inlet_chords at min(c_vals) – this function handles that swap; callers just pass the physically-correct inlet/outlet values for the source.- bend_margin_inlet, bend_margin_outletfloat
Stator only: where the side walls switch between vertical and staggered, each as a fraction of the blade’s own chordwise extent measured inward from the nearer edge (leading edge for bend_margin_inlet, trailing edge for bend_margin_outlet). Clamped so the vertical sections never cross the LE/TE-angle- lines’ own intersection point. The rotor’s own transition points are the natural chordwise overlap of its own suction surface with the blade’s own true LE/TE (see module docstring) – these two params are unused for it.
- turbo_moc.geometry.passage.extract_radial_passage_2d(blade_data, pitch, r1, r2, face_path, solid_path=None, extrude_length=1.0, source='stator', inlet_chords=1.0, outlet_chords=6.0, bend_margin_inlet=0.15, bend_margin_outlet=0.05, n_vertical=25, n_cap=15)[source]#
Conformally maps the SAME periodic passage domain as extract_axial_passage_2d (see its docstring/module docstring for the construction) onto an annular passage between radii r1/r2, using turbo_moc.geometry.radial’s log-spiral wrap – the same mapping already used to wrap blades onto an annulus for Phase 5. One passage, one blade hole (matching n_blades=1 in wrap_curve_radial terms).
IMPORTANT: r1/r2 land at the BLADE’s own leading/trailing edge – same convention as wrap_blade_radial/wrap_rotor_blade_radial – NOT at the passage domain’s own (extended) inlet/outlet caps. The mapping’s reference point/scale (see turbo_moc.geometry.radial’s _reference_point_and_scale) is derived from the blade’s own contour and then shared with the band’s outer boundary, so the band’s inlet/outlet caps (which sit beyond the blade’s LE/TE by
inlet_chords/outlet_chords) extrapolate naturally to radii outside [r1, r2] via the same log-spiral formula, rather than r1/r2 themselves being squeezed onto the (much wider) extended domain.- Parameters:
- blade_data, pitch, source, inlet_chords, outlet_chords,
- bend_margin_inlet, bend_margin_outletsee extract_axial_passage_2d.
- r1, r2float
Inner/outer radii (same length units as blade_data), reached at the blade’s own leading/trailing edge (not the extended domain caps – see above).
- face_path, solid_path, extrude_lengthsee extract_axial_passage_2d.
- n_vertical, n_capint
How densely to resample the domain’s straight vertical/cap segments before mapping (see _dense_boundary_points) – these become log-spiral arcs, not straight lines, once mapped.