Showcase · Design loop

A turbine blade, boxed in by four solvers

The blade as a true NURBS body

The part is the first-stage HP rotor blade of a 42 MW-class aero-derivative natural-gas turbogenerator: 80 blades behind a 47-vane nozzle row, on a 330 mm hub radius, 60 mm of span, spinning at 11,000 rpm, which is about 45,000 g at the root. Those four numbers are declared — this stage is a design of ours, not a machine anyone has measured, and 47 is prime so it shares no factor with the 80. Three numbers were free to move — the trailing-edge thickness, the fir-tree neck width and the blade height — and four independent solvers were asked, at every point, whether the blade was still acceptable. Each solver draws one wall of a feasible box. The nominal blade fails one of them (castability); the point the loop picked inside the box — tTE 1.6 mm, neck 9 mm, height 60 mm — passes all four. The body below is that same picked point, rebuilt as a true NURBS body with the same 1.5 mm one-ball root fillet. The model is solid and uncooled — see solid, not cooled.

The B-rep is an aerofoil now — STEP, the boolean union onto the root, the fillet spine and any mesh built off this file all see a surface, not 538 flat-ish patches standing in for one — built with a bicubic skin, four faces per band, and blended with a single rolling-ball root fillet that holds all the way round the root loop, including the U-turn the leading edge puts in it. It is its own body, with its own STEP download and its own numbers below.

Drag to orbit, scroll to zoom. The selector swaps the skin in the same viewer, so the camera survives the comparison.

Display
Material
View

1–5 switch display mode; i f t s switch view. Your choice is remembered and survives a skin swap.

Loading the NURBS blade…

Before / after — the same picked point, two skins

the picked blade as it was — polyline sections, bicubic-loft skinthe same picked point — bicubic four-face-per-band skin, one-ball root fillet
body faces (post-fillet)57147
plane faces2929
cylindrical faces44
B-spline surface faces53814
STEP file2.7 MB1010 KB
root fillet construction177-edge loop, 167 band runs + 10 corner fans (387 → 564 faces, this fillet alone)4-edge loop, 4 band runs + 2 corner fans
fillet kernel time~8 s geometry + ~10 s closing audit (~30.4 s call, host)4.5 s (the loop's own reported time)
fit vs. the analytic aerofoilno curve fit — the section threads its own raw points (119 of them per station) facet by facet0.0033 mm from the analytic aerofoil, 60 stations
geometry integritycheckFull clean (290 findings, 0 errors); watertight 0/0/0checkFull clean (2 findings, 0 errors); watertight 0/0/0

Every number above is read from a file at build time — the two STEP files' own topology and a live checkFull / watertight pass on each (measured this run), the spline body's own picked_spline.census.json, and the polyline body's root-fillet construction as it was measured when that fillet was first built — never typed in.

The four walls below are measured on this body. Every point of the design-loop study was rebuilt as a spline-section blade with the same one-ball root fillet and re-run through every solver, so the verdicts, the ladders and the box figure all describe the skin you are looking at and the files you can download — not the earlier facet-heavy one, which survives on this page only as the “Faceted skin” button above and the before column of the table.

The box, one axis at a time

Each panel is one design variable. Every dot is a point that was actually built and judged — green passed, red failed, hollow means the solver could not judge it and so drew nothing. A shaded band is a wall: the interval between the last point a solver rejected and the first it accepted. Two of the four never bite inside these ranges, and the notes under each panel say why.

The constraint box: where each of the four walls sits on each design variable Trailing-edge thickness tTE mm — castability draws the lower wall; nothing draws an upper one castability: fails 0.8 → passes 1.2 castability castability at 0.4: fail (measured 0.4094) castability at 0.8: fail (measured 0.8117) castability at 1.2: pass (measured 1.2116) castability at 1.6: pass (measured 1.6098) castability at 2: pass (measured 2.0009) aero aero at 0.4: pass (measured 1.0000) aero at 0.8: pass (measured 1.0031) aero at 1.2: pass (measured 1.0120) aero at 1.6: pass (measured 0.9522) aero at 2: pass (measured 0.9708) 0.4 0.8 0.9 1.2 1.6 2 nominal 0.9 ✗ picked 1.6 ✓ aero: Cd/Cd_ref stays between 0.952 and 1.012 across the whole ladder — flat to ±5 %, inside the stated band, so it never bites. The reason is resolution: the flow grid's cell is 4.3 mm, so a 1.6 mm trailing edge is smaller than one cell — the solver cannot see the edge the study is moving. Fir-tree neck width mm — rim load is the wall on this axis, and it never bites inside the range rim load rim load at 7: pass (measured 1.3292) rim load at 9: pass (measured 1.3255) rim load at 11: pass (measured 1.3219) rim load at 13: pass (measured 1.3185) rim load (rim ladder) rim load at 6: pass (measured 1.3311) rim load at 8: pass (measured 1.3274) rim load at 10: pass (measured 1.3237) rim load at 12: pass (measured 1.3203) rim load at 14: pass (measured 1.3167) 6 7 8 9 10 11 12 13 14 nominal & picked 9 ✓ rim load: 1.32–1.33 ≥ 1.3 everywhere on the ladder — a thicker neck adds blade mass and walks the burst margin down, but far too slowly to reach the limit inside the range. Blade height above the platform mm — one solver, both walls: too tall rubs, too short gives the efficiency away tip clearance: fails 59.5 → passes 60 tip clearance: fails 60.5 → passes 60 tip clearance tip clearance at 58: fail (measured 2.7500) tip clearance at 59: fail (measured 1.7500) tip clearance at 59.5: fail (measured 1.2500) tip clearance at 60: pass (measured 0.7500) tip clearance at 60.5: fail (measured 0.2500) tip clearance at 61: fail (measured -0.2500) tip clearance at 62: fail (measured -1.2500) 58 59 59.5 60 60.5 61 62 nominal & picked 60 ✓ The picked point keeps the nominal height: the box is one ladder step wide here, and 60 mm is the only measured height inside it.

Four walls, four solvers

One card per solver: what it measured, its verdict at the nominal and at the picked point, which variable it bounds, its own basis string verbatim, and what it does not claim. Every number is quoted with its source, and nothing here is a second solver's number wearing this one's label.

cad_dfm_check

Castability

It measures the thinnest material the investment-casting pack can find on the body — the minimum castable section against the 1.0 mm floor it publishes for a nickel superalloy at blade scale, or, where the pack’s thin-edge detector fires on a planar dihedral, that edge against its 0.6 mm floor. The verdict names the rule it led with in details.leadRule.

pointmeasuredlimitmargin
nominal (tTE 0.9, neck 9, h 60)0.914 mm1.0 mm-0.086FAIL
picked (tTE 1.6, neck 9, h 60)1.610 mm1.0 mm+0.610PASS

It draws the lower bound on tTE — 0.8 fails, 1.2 passes.

tTE ladder — the tTE ladder 0.4…2.0, one loop, one aero reference
tTEmeasured
0.40.409 mmFAIL
0.80.812 mmFAIL
1.21.212 mmPASS
1.61.610 mmPASS
22.001 mmPASS
Basis, verbatim from the verdict

investment-casting design guides publish a ~1.0-1.5 mm minimum castable wall for a nickel-superalloy aerofoil section at blade scale — thinner sections misrun or cold-shut before the ceramic mould fills; heavier industrial-frame sections tolerate more (params.minSectionMm)

cad_mass_properties · closed-form disc stress

Rim load

It measures the disc's burst-speed ratio with 80 of these blades pulling on the rim — the kernel's own mass and centre of gravity go in, the average-tangential-stress criterion at 0.9·UTS comes out. Any hoop stress quoted on this card is closed-form disc stress — our own arithmetic, not an FEA result.

pointmeasuredlimitmargin
nominal (tTE 0.9, neck 9, h 60)1.3255×1.30 burst speed ratio+0.026PASS
picked (tTE 1.6, neck 9, h 60)1.3238×1.30 burst speed ratio+0.024PASS

It bounds nothing in this box: it passes at every measured point on every axis it was asked about.

neckWidth ladder — the neck ladder 7…13
neckWidthmeasured
71.3292×PASS
91.3255×PASS
111.3219×PASS
131.3185×PASS
neckWidth ladder — the rim-load wall alone across the neck ladder 6…14
neckWidthmeasured
61.3311×PASS
81.3274×PASS
101.3237×PASS
121.3203×PASS
141.3167×PASS
Basis, verbatim from the verdict

Timoshenko rotating annulus + Lamé rim tension, average-tangential-stress burst criterion at 0.9·UTS of the disc alloy at its rim temperature; the blade's mass and r_cg are the kernel's

cad_tolerance_stack

Tip clearance

It measures the hot running tip clearance as a six-member radial stack — casing bore and its growth, disc rim and its growth, blade height and its growth — judged on the RSS resultant against a 0.3–1.5 mm running window.

pointmeasuredlimitmargin
nominal (tTE 0.9, neck 9, h 60)0.75 mm0.3..1.5 mm hot running clearance (RSS)+0.148PASS
picked (tTE 1.6, neck 9, h 60)0.75 mm0.3..1.5 mm hot running clearance (RSS)+0.148PASS

It draws the lower bound on bladeHeight — 59.5 fails, 60 passes; it draws the upper bound on bladeHeight — 60.5 fails, 60 passes.

At the picked point the RSS resultant runs 0.45–1.05 mm (low margin +0.148 mm); the worst case runs 0.07–1.43 mm, which is outside the window at the tight end by 0.230 mm. Both are shown because a stack judged only on its RSS is a statistical claim, not a build guarantee.

bladeHeight ladder — the tip-clearance wall across 58…62
bladeHeightmeasured
582.75 mmFAIL
591.75 mmFAIL
59.51.25 mmFAIL
600.75 mmPASS
60.50.25 mmFAIL
61-0.25 mmFAIL
62-1.25 mmFAIL
Basis, verbatim from the verdict

Running tip clearance stacks 5 contributors: casing bore radius, disc rim radius, blade height, and the thermal growth of the casing and the disc/blade assembly — each typically +/-0.1 to +/-0.6 mm, summing to the cold-build allowance tip-clearance-targets budgets for. Judged on the RSS resultant (independent contributors), worst case reported; the casing and disc growth terms carry the hot-day (>43 °C ambient) design point.

cad_wind_tunnel

Aero

It measures the section's drag coefficient as a ratio to the thinnest trailing edge in the same ladder, on the same grid and the same residual target.

pointmeasuredlimitmargin
nominal (tTE 0.9, neck 9, h 60)1.0062 Cd/Cd_ref1.03 Cd/Cd_ref+0.024PASS
picked (tTE 1.6, neck 9, h 60)0.9522 Cd/Cd_ref1.03 Cd/Cd_ref+0.078PASS

It bounds nothing in this box: it passes at every measured point on every axis it was asked about.

tTE ladder — the tTE ladder 0.4…2.0, one loop, one aero reference
tTEmeasured
0.41.0000 Cd/Cd_refPASS
0.81.0031 Cd/Cd_refPASS
1.21.0120 Cd/Cd_refPASS
1.60.9522 Cd/Cd_refPASS
20.9708 Cd/Cd_refPASS
Basis, verbatim from the verdict

Cd from the vendored MAC Navier–Stokes solver is comparative, never certified; judged as a ratio to the thinnest-TE reference at the same grid, outside a stated band

What the kernel refused — and what it no longer refuses

The blade asks for a 1.5 mm airfoil-to-platform root fillet at every point in the study. It is cut now, on every body this page ships: each one was rebuilt for this box on 2026-09-12 and carries one rolling ball around the whole root loop. The first time this study ran, the kernel refused that step and the refusal was recorded rather than worked around — no fillet was faked. What follows is that refusal as history, and then the measurement that replaced it.

That refusal is history, and the honest thing is to say so on the same page that published it. The kernel has since learned to roll a ball along a reentrant plane × B-spline junction, and to carry it continuously around a closed root loop. Re-run against the shipped body, the same call now succeeds: one rolling ball around the whole 177-edge, 91.47 mm root loop at r = 1.5 mm, 391 → 575 faces, +44.12 mm³ against a rolling-ball bound of 44.17 mm³ (0.999×), watertight, checkFull clean, STEP round trip exact.

The bodies below are the filleted ones, and the whole box was re-measured on them in one pass — so what the blend costs is not a prediction on this page, it is the verdict above. At the picked point the investment-casting check reads min_section 1.610 mm against its 1.0 mm floor, min_trailing_edge_thickness reports no knife edge at the 1.6 mm trailing edge, and min_fillet_radius 0 mm — exactly where it was before the blend, because it was never pointing at this junction. On the earlier faceted skin the same blend was authored as sub-millimetre band pieces, one per facet patch, and it cost real section thickness; on the NURBS skin it does not. The page ships the body the study measured — never a filleted blade against verdicts measured on a sharp one.

Hollowing the airfoil for cooling: refused, not attempted-and-hidden

Cooling the blade starts with a shell. cad_shell was tried on the shipped body — picked.step, 391 faces, 987 edges, 27,708.94 mm³, watertight — and refused at every thickness tried, on 2026-09-08:

E_GEOMETRY — cad_shell, thickness 1.2 mm, 2026-09-08

shell-vertex-unsolvable — “vertex #1494 - no point lies on all 3 of its adjacent faces' offset surfaces at thickness 1.2 (the corner is not uniformly offsettable; split the vertex or reduce thickness)”.

E_GEOMETRY — cad_shell, thickness 0.6 mm, 2026-09-08

shell-vertex-unsolvable — “vertex #5035 - no point lies on all 4 of its adjacent faces' offset surfaces at thickness 0.6, and its offset half-spaces admit no certifiable split tip”.

Thinner does not help: the failure moves to a different, higher-valence vertex. This is a corner solve, not a thickness limit — the kernel already offsets the NURBS surfaces themselves (to 4e-15 deviation on a lofted test body); what is missing is the offset corner, where several offset surfaces do not meet in one point. That corner solve is what stands between this blade and a cored one.

The cooling core as a subtract body: the core builds, the boolean refuses

A core is not a shell: it is its own solid, built and then subtracted, exactly as the ceramic core is a real object in the real process — so we built one (5 lofted pieces — radial passes inset 1.0 mm from the skin along its own normal, with 180° turn-arounds at alternating ends) and tried to subtract it. The core itself is sound. Every piece lofts watertight, and each built volume agrees with the analytic passage volume to better than 0.14 % (worst: pass1, 1243.0 mm³ analytic vs 1241.3 mm³ built).

The boolean is what refuses. Every exact rung of the ladder was run against the shipped body and recorded:

rungwhat it askswallverdicttime
Adesign wall, core assembled first1.0 mmE_GEOMETRY / coplanar_face_merge_unsupported36049 ms
Bdesign wall, five separate subtracts1.0 mmE_KERNEL_OOM48163 ms
Ccoarser wall, one passage (three do not fit)1.5 mmbuilt
Done passage, no ribs, no turns1.0 mmbuilt
Edesign wall through the FACETED fallback: one planar face per triangle, an explicit precision downgrade, recorded as such1.0 mmE_KERNEL_OOM48098 ms
Frung D through the faceted fallback — one passage, one mesh boolean, so the fallback's cost is measured on its own before the five-piece rung E1.0 mmE_KERNEL_OOM51965 ms
Gstraight radial drilled passages at the same 1 mm wall — an analytic tool against the same B-spline skin, so what separates it from rungs A-D is the TOOL's surface class, not the wall1.0 mmE_KERNEL_OOM64156 ms
Hthe same straight radial passages through cad_drill_hole (the documented robust route for a round hole) rather than a cylinder and a boolean1.0 mmE_GEOMETRY / curved_param_inversion5080 ms
Pthree passes as three exact cavities, no turns1.0 mmbuilt

Two measurements are worth reading twice. A 1.5 mm wall refuses with the same curved_param_inversion as a 1.0 mm one, so what refuses is the boolean class, not the clearance. And every refusing rung names the same point on the base body — [18.672117, 4.193846, 1.185133], a trim-loop point on a B-spline face at the hub trailing edge, which evaluates 4.736×10−3 mm off its own surface against a 1.021×10−3 mm band. It is the same point for a serpentine core, for a straight drilled passage 20 mm away, and at both walls, so it is a property of the shipped body's trim data rather than of the tool. The blade still measures watertight and checkFull-clean: the boolean's band is the tighter of the two. Nothing on this page is cored, and every wall above is still measured on the solid blade.

Natural frequencies

A different question from the four above, asked once, of the one blade the loop picked: what does it ring at? This is not another wall — it bounds nothing, no point was accepted or rejected on it, and the box figure is unchanged. It is the first 8 global undamped natural frequencies of the picked blade, held at its fir-tree root, solved with CalculiX 2.21 and read back out of the solver's own files. 20 modes were solved to get these 8; what the other 12 were, and why none of them belongs on this page, is below the table.

The frequency table is rendered in your browser from turbine-blade/modal/results.json — open it directly if scripting is off.

Γx / Γy / Γz are the participation factors, in the blade's own frame: +Z is the stacking axis out of the platform, +X is the engine axis and +Y is the direction of rotation. The dominant one is how the mode reads — a Γy mode is flapwise, a Γx mode edgewise. Every row here is a mode of the whole blade: the local ones the solver also returned were measured and rejected before this table was written, and each is named below with the measurement that rejected it.

a second 3-D view and about 3 MB of shape data — it loads itself when this section reaches the screen; there is nothing to click.

What the guard threw away

CalculiX was asked for 20 modes and the table above carries 8. The difference is not editing. A mass-normalised eigenvector has no physical scale, so a mesh with near-degenerate elements can hand back a “mode” whose entire shape sits on two or three nodes — a sliver ringing, not the blade — and one row here came back with a negative eigenvalue, which is not a frequency under any reading. Nothing downstream could tell those from the real thing, so the reducer measures every solved mode before it writes the table: peak |φ| divided by its 99th percentile over the 6,039 drawn surface nodes. Over 10 and the mode is local and is not published.

The threshold is not a close call. The 8 published modes score 1.0–5.5; every rejected one is in the table below, and the nearest of them is 1.3 × 10³. There is no judgement in that gap. The rejects are the mesh, not the blade: the same elements the kernel's own audit grades as slivers. Fix those and the gap closes from the other side.

every solved mode the guard did not publish — the reducer's own numbers
solver modefrequencypeak ÷ p99 of |φ|nodes carrying a tenth of the peakverdict
1none — the eigenvalue is negative4.4 × 10¹³2 of 6,039refused: a non-positive eigenvalue is not a frequency
21.38 Hz6.7 × 10¹⁴2 of 6,039local: a feature ringing, not the blade
41338.2 Hz5.5 × 10⁹2 of 6,039local: a feature ringing, not the blade
52331.0 Hz7.0 × 10⁷1 of 6,039local: a feature ringing, not the blade
85439.8 Hz8.7 × 10⁵1 of 6,039local: a feature ringing, not the blade
107821.5 Hz4.0 × 10⁸2 of 6,039local: a feature ringing, not the blade
119762.2 Hz1.7 × 10⁶1 of 6,039local: a feature ringing, not the blade
1514.44 kHz5.7 × 10⁸2 of 6,039local: a feature ringing, not the blade
2022.95 kHz1.3 × 10³1 of 6,039local: a feature ringing, not the blade

3 further modes passed the guard and are not shown, because the table stops at 8: 16.52 kHz, 19.12 kHz, 19.77 kHz. They are in results.json under localisationGuard.surplusGlobal.

How far to trust the number

The same solver, the same element and the same case pipeline were run against two bodies whose frequencies are known in closed form. That is the evidence behind the table above; the blade itself has no closed form to check against.

First three modes, second-order tetrahedra vs closed form — the solver’s validation ladder
rungclosed formmode 1mode 2mode 3
cantilever beam 100 × 5 × 5 mmTimoshenko (L/h = 20)+0.36 %+0.18 %+0.45 %
cantilever plate 60 × 60 × 3 mmLeissa NASA SP-160 Table 4.49+0.17 %+2.24 %−0.14 %

The ladder's target is 5 % on the first three modes and both rungs meet it with margin. The outlier is the plate's torsion mode at +2.24 %, which is where a single layer of second-order tetrahedra through a 3 mm slab is expected to be stiff.

A second solver: pending. The same case is written as a Nastran SOL 3 deck and shipped below, but no MYSTRAN build could be run on any machine this was measured on, so nothing here has been solved twice. There is therefore no cross-solver agreement band on this page and no second column: these frequencies are comparative, not certified — one solver, validated against closed form on the ladder above, with no cross-solver spread measured. Any Nastran-format solver can run the deck and report its own column beside this one.

Not modeled

Everything below is absent from this run by design. None of it is approximated, and none of it is hinted at by the table — a frequency here is the frequency of a stationary, cold, undamped, single blade and nothing else.

json the frequency table, as the solver reported it 7 KB json the mode shapes on the surface nodes, for the viewer 1.0 MB inp the CalculiX *FREQUENCY deck this was solved from 5.5 MB bdf the same case as a Nastran SOL 3 deck — unsolved, see below 7.7 MB

The mesh

This is the mesh the frequencies above were solved on. It is the exact deck CalculiX solved — the C3D10 tetrahedra parsed back out of turbine-blade/modal/case.inp — graded tet by tet by the kernel's own VolumeMesher.quality() audit.

The mesh audit is rendered in your browser from turbine-blade/modal/mesh-quality.json — open it directly if scripting is off.

a 3-D view of this exact mesh and its per-tet quality, and about 1.5 MB of node/tet/adjacency data — it loads itself when this section reaches the screen; there is nothing to click until then.
json the mesh audit — counts, histograms, worst tets, surface and edge statistics 7 KB bin the mesh itself — corner nodes, tets, face adjacency and per-tet quality, packed for the viewer 1.5 MB

Solid, not cooled

The model is solid. A first-stage HP rotor blade of this class, IN738LC at 850 °C, is internally cooled; this one is not, and every wall above is measured on the body the page ships — no internal cooling geometry at all: no serpentine core, no film-hole rows, no trailing-edge discharge. That is a kernel limit, not a modelling choice: the shell needed to hollow it is refused at every thickness tried, recorded in What the kernel refused above.

Three of the four published walls would read differently once the blade is cored, and the difference is not cosmetic:

The blade is solid because the kernel cannot yet hollow it, and the page says so rather than drawing cooling it did not build.

How it was run

One driver, four verdict functions, one run per point. The driver calls the NativeCAD tool surface exactly as an agent does, and every wall is a verdict function:

castability   cad_dfm_check { solid: $body, process: 'investment_casting', params: { maxSectionRatio: 25 } }
rimLoad       cad_mass_properties → closed-form disc stress (Timoshenko rotating annulus + Lamé rim tension)
tipClearance  cad_tolerance_stack { members: 6 radial contributors, limits: { lower: 0.3, upper: 1.5 } }
aero          cad_wind_tunnel { solid: $body, gridRes: "fast", velocity: 100, residualTarget: 0.01 }

Each point was built from scratch (a cubic NURBS aerofoil skin unioned onto an analytic platform / shank / fir-tree root, exported as STEP AP242 and STL) and then judged. 6 runs, 23 measured points, kernel 6cdaec88, run 2026-09-12 to 2026-09-12.

Take the files

The picked point, as the kernel wrote it: STEP AP242 and the STL the solvers were handed, plus a GLB for every point the box study built — the picked point, the nominal, and the six points at each wall's ladder ends. None of them load in a viewer on this page anymore; they open in any glTF viewer (the GLBs) or any STEP/STL viewer (the rest). Each GLB is built from its point's own STEP, not the STL: the kernel tessellates the B-rep so the shading uses the surfaces' own normals, and every B-rep edge is sampled off its own curve and shipped in the file as a line set, so the edge overlay is the model's edge set rather than a guess at one from triangle angles.

GLB The picked point — tTE 1.6, neck 9, height 60 205 KB GLB The nominal — tTE 0.9, neck 9, height 60 240 KB GLB tTE 0.4 mm — the thinnest trailing edge 239 KB GLB tTE 2.0 mm — the blunt end of the ladder 242 KB GLB neck 7 mm — the thin end of the ladder; rim load passes 240 KB GLB neck 13 mm — the thick end of the ladder; rim load passes 221 KB GLB height 58 mm — clearance opens past the budget 240 KB GLB height 62 mm — the tip is into the casing 240 KB STEP the picked blade (tTE 1.6, neck 9, h 60) 1010 KB STL the picked blade (tTE 1.6, neck 9, h 60) 1.3 MB STEP the picked blade as a true NURBS body (tTE 1.6, neck 9, h 60) — bicubic skin, one-ball root fillet 1010 KB

More demos

All demos →

Build your own part with NativeCAD

Free for education and makers with a registered key · $200 per seat per year · Kernel SDK for products.