Skip to content

fix(su2): CRLF crashes, FFD/NPERIODIC warning spam, and point column trim - #1552

Open
AhmedMoustafaa wants to merge 1 commit into
nschloe:mainfrom
AhmedMoustafaa:fix-su2-crlf-periodic
Open

fix(su2): CRLF crashes, FFD/NPERIODIC warning spam, and point column trim#1552
AhmedMoustafaa wants to merge 1 commit into
nschloe:mainfrom
AhmedMoustafaa:fix-su2-crlf-periodic

Conversation

@AhmedMoustafaa

Copy link
Copy Markdown

Fix SU2 reader: CRLF line endings, double-trim bug, NPERIODIC and FFD sections

Summary

This PR fixes four bugs in the SU2 mesh reader that together caused 4 crashes and
134,634 spurious warnings when reading SU2 v7/v8 tutorial meshes. After the patch,
all 50 tutorial meshes load successfully with only 454 expected warnings (string tag
substitutions).

Metric Before After Delta
Failures 4 0 -4
Total warnings 134,634 454 -134,180

Fixes

1. CRLF line endings crash the point coordinate reader

Affected files: any SU2 mesh generated on Windows or by certain solvers (e.g.
CIRA, commercial CFD exporters).

np.fromfile(..., sep=' ') uses C-level I/O and bypasses Python's text-mode
\r\n → \n translation. On CRLF files, the \r characters are treated as
non-numeric tokens and stop the read early, producing a reshape error:

ValueError: cannot reshape array of size 259228 into shape (51846,5)

This crashed 4 meshes in the tutorial suite:

compressible_flow/ActuatorDisk_VariableLoad/propeller_variable_load.su2
compressible_flow/Transitional_Flat_Plate/grid.su2
compressible_flow/Transitional_Flat_Plate/Langtry_and_Menter/T3A/grid.su2
multiphysics/unsteady_fsi_python/airfoil.su2

All four have 100% CRLF line endings. The fix replaces np.fromfile with explicit
line-by-line reading, which is handled correctly by Python's text mode:

# Before (broken on CRLF files):
points = np.fromfile(
    f, count=num_verts * (dim + extra_columns), dtype=ftype, sep=" "
).reshape(num_verts, dim + extra_columns)
 
# After (safe on both LF and CRLF):
raw = [f.readline().split()[:dim] for _ in range(num_verts)]
points = np.array(raw, dtype=ftype)

2. Double-trimming of extra point columns

This bug was introduced alongside the CRLF fix. After switching to line-by-line
reading with [:dim] slicing, points already has exactly dim columns.
The subsequent points[:, :-extra_columns] then incorrectly trims real coordinate
data. Fix: remove the redundant column trim from points; keep it only on
first_line which is still built from the full-width raw line:

# Before (trims already-clean data):
if extra_columns > 0:
    first_line = first_line[:-extra_columns]
    points = points[:, :-extra_columns]   # ← wrong, points is already [:dim]
 
# After:
if extra_columns > 0:
    first_line = first_line[:-extra_columns]
    # points already sliced to [:dim] during line-by-line read

3. NPERIODIC section causes spurious warnings

SU2 turbomachinery meshes (e.g. propeller, compressor cases) append a NPERIODIC
block after the boundary markers. Its data lines contain no = sign, so the main
parser loop emitted a warning for each one:

Warning: meshio could not parse line
 0.000000000000000e+00  0.000000000000000e+00  0.000000000000000e+00
 skipping.....

Fix: explicitly skip the data lines following NPERIODIC and PERIODIC_INDEX:

elif name == "NPERIODIC":
    nperiodic = int(rest_of_line)
    for _ in range(nperiodic):
        f.readline()  # PERIODIC_INDEX= n
        f.readline()  # translation vector
        f.readline()  # rotation center
        f.readline()  # rotation angles

4. FFD box sections cause massive warning spam

SU2 shape optimisation meshes embed Free-Form Deformation (FFD) box definitions
between the mesh header and the element data. Three sub-sections —
FFD_CORNER_POINTS, FFD_CONTROL_POINTS, and FFD_SURFACE_POINTS — each have
a count followed by bare data lines with no = sign. The parser emitted a warning
for every single line, producing tens of thousands of spurious warnings per mesh:

Warning: meshio could not parse line
 -0.0403        0       -0.04836
 skipping.....
Warning: meshio could not parse line
  0.8463        0       -0.04836
 skipping.....
... (60,000+ times)

Fix: skip the N data lines following each of the three keywords:

elif name == "FFD_CORNER_POINTS":
    for _ in range(int(rest_of_line)):
        f.readline()
 
elif name == "FFD_CONTROL_POINTS":
    for _ in range(int(rest_of_line)):
        f.readline()
 
elif name == "FFD_SURFACE_POINTS":
    for _ in range(int(rest_of_line)):
        f.readline()

Note: other FFD_* keywords (FFD_TAG, FFD_DEGREE_I/J/K, FFD_LEVEL,
FFD_PARENTS, FFD_CHILDREN) have their value on the keyword line itself and are
already silently handled by the generic split("=") fallthrough — no change needed
for those.


Per-file impact

File Status Warnings before Warnings after Delta
compressible_flow/Inviscid_ONERAM6/mesh_ONERAM6_inv_ffd.su2 pass 60,320 14 -60,306
design/Inviscid_3D_Constrained_ONERAM6/mesh_ONERAM6_inv_FFD.su2 pass 60,320 14 -60,306
design/Inc_Turbulent_Bend_Wallfunctions/sudo_coarse_FFD.su2 pass 8,120 8 -8,112
multiphysics/steady_cht/mesh_cht_3cyl_ffd.su2 pass 2,733 21 -2,712
design/Unsteady_Shape_Opt_NACA0012/unsteady_naca0012_FFD.su2 pass 1,402 4 -1,398
incompressible_flow/Inc_Streamwise_Periodic/fluid_FFD.su2 pass 396 12 -384
design/Multi_Objective_Shape_Design/mesh_wedge_inv_FFD.su2 pass 311 8 -303
incompressible_flow/Inc_Species_Transport/1__FFD-box-writing/mesh_out.su2 pass 172 10 -162
incompressible_flow/Inc_Species_Transport/2__mesh-deform-test/primitiveVenturi.su2 pass 172 10 -162
incompressible_flow/Inc_Species_Transport/3__gradient-validation/primitiveVenturi.su2 pass 172 10 -162
incompressible_flow/Inc_Species_Transport/4__optimization/primitiveVenturi.su2 pass 172 10 -162
compressible_flow/Turbulent_ONERAM6/mesh_ONERAM6_turb_hexa_43008.su2 pass 39 6 -33
compressible_flow/Turbulent_ONERAM6/mesh_ONERAM6_100k.su2 pass 15 6 -9
structural_mechanics/cantilever/mesh_cantilever.su2 pass 11 8 -3
multiphysics/unsteady_fsi_python/airfoil.su2 fail→pass 0 4 +4
compressible_flow/ActuatorDisk_VariableLoad/propeller_variable_load.su2 fail→pass 0 10 +10
compressible_flow/Transitional_Flat_Plate/Langtry_and_Menter/T3A/grid.su2 fail→pass 0 10 +10
compressible_flow/Transitional_Flat_Plate/grid.su2 fail→pass 0 10 +10

Remaining warnings (454 total)

All remaining warnings are expected and pre-existing — meshio does not support
string boundary tags and substitutes integers:

Warning: meshio does not support tags of string type.
    Surface tag  inlet will be replaced by 1
Warning: meshio does not support tags of string type.
    Surface tag  outlet will be replaced by 2

These are a separate issue unrelated to this PR.


Test setup

Tested against all 50 .su2 mesh files from the
SU2 v8.0 tutorial repository covering
compressible flow, incompressible flow, multiphysics, structural mechanics, and
shape design cases.

@AhmedMoustafaa
AhmedMoustafaa marked this pull request as draft March 22, 2026 15:52
CRLF line endings caused np.fromfile to stop reading early,
crashing 4 meshes with a reshape error. FFD box sections and
NPERIODIC blocks contain bare data lines with no "=" sign,
generating up to 60,000 spurious warnings per mesh.
UnboundLocalError when NPOIN section is absent was also fixed.

Replace np.fromfile with line-by-line reading to handle CRLF,
skip data lines under FFD_CORNER_POINTS, FFD_CONTROL_POINTS,
FFD_SURFACE_POINTS, and NPERIODIC sections, and initialize
points to an empty array as a safe default.

Tested on all 50 SU2 v8 tutorial meshes:
- Failures: 4 -> 0
- Total warnings: 134,634 -> 454
@AhmedMoustafaa
AhmedMoustafaa force-pushed the fix-su2-crlf-periodic branch from 4c6fe6f to 97619f5 Compare March 22, 2026 16:02
@AhmedMoustafaa
AhmedMoustafaa marked this pull request as ready for review March 22, 2026 16:03
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.

1 participant