Polars follow table_format through the node-table I/O, and lose csv from their names - #372
Conversation
…e_format read_node_table / write_node_rows take named value columns and an optional delta column, so a POLAR_VECTORS or POLAR_MATRICES table is one of their tables: the polar writers and load_polar_data go through them, CSV or Arrow by suffix. csv_fields moves beside them as the one CSV row formatter. generate_airfoils names the polar with the table_format suffix, and migrate_node_tables converts a cached dataset's polar too, now also on surfplan_to_aero_yaml's reuse path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1-Bort-1
left a comment
There was a problem hiding this comment.
Independent review (advisory)
Verdict: APPROVE WITH COMMENTS · 3 inline, 0 off the diff
Good
- Delivers what the card promises:
generate_airfoilsnames the polarpolars/{j}.{table_format}, andmigrate_node_tablesnow includescsv_file_path. Checked ingeometry_gen.jl:41andobj_to_yaml.jl:129. - Keeps one codepath: the three polar writers,
convert_node_tableandload_polar_dataall go throughread_node_table/write_node_rows, andcsv_fieldsis now the only CSV row formatter. Grep finds no other polar parser insrc. - Removes the 90-line hand parser in
load_polar_data. It also fixes the oldload_polar_datadocstring, which sat onassemble_polar_matrix; that function now has its own accurate docstring. write_polar_csv(sols)keeps alpha in radians andwrite_node_rowsdoes the degree conversion. The NeuralFoil method passesdeg2rad.first. Both land in degrees, the same as before.- The legacy Arrow read falls back to
n0, n1, …names when there is no metadata, and a test covers it (test_airfoil_aero.jl:363). The existingread_section_aerocall that unpacks three of the four return values still works. - The surfplan reuse branch was a real gap: it returned the old YAML untouched. It now migrates, and a test covers it (
test_surfplan.jl:41-46). - The card explains why it departs from the issue sketch (per-width Arrow compile) and gives measured timings, so the metadata-column layout is justified.
Not good
src/section_aero.jl:169—data[:, value_cols]copies the whole value matrix afterread_arrow_columnshas already filleddata. Every Cp/cf load inread_section_aeronow allocates the node table twice, on the path that Arrow is meant to speed up.src/section_aero.jl:213—read_csv_columnsparses every column as Float64. A polar CSV with an extra non-numeric or empty column now fails, where the oldload_polar_dataparsed only alpha/cl/cd/cm, andload_polar_datathen falls back to INVISCID with only a warning. The card mentions the stricter field count but not this, and the CHANGELOG says 'CSV polars load as before'.src/airfoil_aero/airfoil_solvers/common.jl:44— Destructuring a generator ofgetfieldcomprehensions over a tuple of field names is the 'clever comprehension chain' that §3 rules out. Four plain[sol.alpha for sol in converged]lines, or one loop, would read at a glance.docs/src/airfoil_pipeline.md:100still listspolars/{j}.csv, while the paragraph at :109 says the polar followstable_format. The bullet should readpolars/{j}.{table_format}, the same asobj_to_yaml's docstring.- CHANGELOG line 29, "and now also
surfplan_to_aero_yaml", only makes sense next to the previous version (§7 countermand). State what both functions do. - The test at
test_airfoil_aero.jl:346and:356states the expected column names twice with two different ternaries. Put the expected columns in thewriterstable next to each writer. write_node_rowsbuildshcat(angles..., values), a full copy of the node matrix, only to format CSV rows. This runs on every node-table write, not just for polars.- The card lists
_csvnames that no longer fit and acsv_file_pathkey that can now point at an.arrowfile. No follow-up issue is linked for that breaking rename.
claude, rubric CLEAN_CODE.md. A different lab from the implementer
on purpose: a reviewer sharing its blind spots would not flag its mistakes.
| delta_col = findfirst(==("delta"), lowercase_names) | ||
| value_cols = setdiff(eachindex(names), (alpha_col, delta_col)) | ||
| delta = delta_col === nothing ? nothing : deg2rad.(data[:, delta_col]) | ||
| return deg2rad.(data[:, alpha_col]), delta, data[:, value_cols], names[value_cols] |
There was a problem hiding this comment.
MINOR: data[:, value_cols] copies the whole value matrix after read_arrow_columns has already filled data. Every Cp/cf load in read_section_aero now allocates the node table twice, on the path that Arrow is meant to speed up.
There was a problem hiding this comment.
Fixed in e0a1f58: read_node_table returns a view of the value columns. A 600 × 151 Arrow table now allocates 1.80 MB to read, down from 2.52 MB. write_node_rows also no longer hcats before writing the CSV rows.
| length(fields) == length(names) || | ||
| error("Row $k of $path has $(length(fields)) fields, header $(length(names))") | ||
| @inbounds for j in eachindex(fields) | ||
| data[k, j] = parse(Float64, fields[j]) |
There was a problem hiding this comment.
MINOR: read_csv_columns parses every column as Float64. A polar CSV with an extra non-numeric or empty column now fails, where the old load_polar_data parsed only alpha/cl/cd/cm, and load_polar_data then falls back to INVISCID with only a warning. The card mentions the stricter field count but not this, and the CHANGELOG says 'CSV polars load as before'.
There was a problem hiding this comment.
Kept strict: e0a1f58 corrects the CHANGELOG line and the card, and a new test_load_polar_data.jl case pins that a non-numeric column loads as INVISCID. Nothing here writes such a column.
| end | ||
| return filepath | ||
| converged = filter(sol -> !isnan(sol.cl), sols) | ||
| alpha, cd, cl, cm = ([getfield(sol, name) for sol in converged] |
There was a problem hiding this comment.
MINOR: Destructuring a generator of getfield comprehensions over a tuple of field names is the 'clever comprehension chain' that §3 rules out. Four plain [sol.alpha for sol in converged] lines, or one loop, would read at a glance.
There was a problem hiding this comment.
Fixed in e0a1f58: four plain comprehensions.
read_node_table returns a view of the value columns instead of a copy,
and write_node_rows formats each CSV row without first hcat-ing the
angles onto the values. write_polar_csv collects its four columns with
plain comprehensions. The polar round-trip test keeps each writer's
expected columns beside it. The pipeline docs name the polar and node
table suffix as {table_format}, and the changelog states that a CSV
polar with a non-numeric column now loads as INVISCID, pinned by a test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Local full suite: PASS (4 min, Julia 1.13.0, one cell of the matrix) |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
fix the first two found on the way points in this PR. we are already preparing a breaking release, so perfect timing. |
… as table_format write_polar_csv is write_polar and write_polar_matrix_csv is write_polar_matrix, and the geometry YAML names the polar polar_file_path; csv_file_path is still read, and migrate_node_tables writes it back under the new key. resolve_airfoil and resolve_aero_geometry take table_format, so the awesIO neuralfoil route writes .arrow polars as well. Closes #373. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ead-polar-tables-as-arrow-whe # Conflicts: # CHANGELOG.md
|
Should we reopen the flaky windows forwarddiff test issue and assign it to 1-Bort-1, bc it is failing on windows again. |
csv from their names
TL;DR
With
table_format=:arrow,obj_to_yaml,surfplan_to_aero_yamlandgenerate_airfoilsnow writepolars/{j}.arrownext to the.arrowCp/cf tables, andload_polar_datareads it. Until now every polar was CSV whatever the setting, so BeyondTheSim's SK100 run withtable_format: arrowstill got CSV polars. There is no second Arrow path: the polar writers and the loader go throughread_node_table/write_node_rows, which now carry column names and an optionaldeltacolumn. Since a polar is no longer necessarily CSV, the writers are renamedwrite_polar/write_polar_matrixand the YAML keypolar_file_path(breaking, for the coming release).What changed
read_node_table(path)returns(alpha, delta, values, columns).deltaisnothingwhen the table has nodeltacolumn, and the columns are found by header name (case-insensitive, any order). APOLAR_MATRICEStable (alpha, delta, Cl, Cd, Cm) and aPOLAR_VECTORStable (alpha, Cd, Cs, Cl, Cm) are therefore both ordinary node tables.write_node_rows(...; columns)writes either.csv_fields(from Write polar CSV coefficients at 16 significant digits instead of 4 decimals #369) moved beside it and is now the only CSV row formatter.write_polar(both methods) andwrite_polar_matrixare now a few lines each on top ofwrite_node_rows, CSV or Arrow as the path's suffix says.load_polar_datalost its 90-line hand parser and callsread_node_table. It still warns and returns(nothing, INVISCID)for a missing, empty or malformed file; the eight existingtest_load_polar_data.jlcases pass unchanged.generate_airfoilsnames the polarpolars/{j}.{table_format}.migrate_node_tablesalso converts the polar, so switching format on a cached dataset rewrites it instead of re-running NeuralFoil.surfplan_to_aero_yaml's reuse branch now calls it too; before, it returned the old YAML untouched.resolve_airfoilandresolve_aero_geometrytaketable_formatas well, so the awesIOneuralfoilroute writes{id}.arrow; it wrote{id}.csvwhatever was asked. Existing CSV datasets load as before.write_polar_csv→write_polar,write_polar_matrix_csv→write_polar_matrix, and the geometry YAML keycsv_file_path→polar_file_path, as Rename write_polar_csv, write_polar_matrix_csv and csv_file_path now that polars can be Arrow #373 proposed and @1-Bart-1 asked for here. The old function names are gone. The old key is still read byWing, because BeyondTheSim's datasets and awesIO-style inputs carry it, andmigrate_node_tableswrites it back aspolar_file_pathwhen it converts a dataset. Every YAML indata/andtest/now uses the new key; a test loads one with the old key.deltacolumn, which the optionaldeltahandles.Where it differs from the issue's sketch
alpha,deltaand a list columnvalues, and the column names go into the schema metadata entrycolumns. That gives one compile for every width. Arrow files written before this PR have no metadata and read withn0, n1, …names (tested). The cost is that pyarrow shows a polar as avalueslist plus metadata, not asCl/Cd/Cmcolumns.join(row, ","); it now usescsv_fields, as the issue asked. That broke the existingarrow.delta_range == back.delta_rangecheck: CSV now writesrad2deg(deg2rad(3))as3, while Arrow stored 2.9999999999999996.write_node_rowsnow rounds the degree angles to the same 16 digits for Arrow as well, and the check passes again unchanged. The coefficients themselves differ between the formats only past the 16th digit.Found on the way, not changed
read_csv_columnsparses every column as a number, and throws on a row whose field count differs from the header. The oldload_polar_dataparsed onlyalpha/cl/cd/cm, so a CSV polar with an extra non-numeric column (asourcelabel, say) now warns and loads asINVISCID. Nothing in this repo or its datasets writes such a column. The CHANGELOG says so, and a test pins it.Searched first for:
write_polar,load_polar_data,resolve_airfoil,read_node_table,write_node_rows,csv_fields,table_format,csv_file_path.Verification
table_format(endswith("polars/1.csv", ".arrow")fails in the migration test).srcwith the new tests:test_airfoil_aero.jlBoundsError(only three return values fromread_node_table),test_surfplan.jlpolars/1.arrowmissing,test_obj_adapter.jlpolar stillpolars/1.csv. Red for the renames on the previous head'ssrc:test_obj_adapter.jl49 passed, 2 failed, 7 errored (resolve_aero_geometryhas notable_format, the key is not rewritten),test_yaml_geometry.jl165 passed, 15 failed, 2 errored (polar_file_pathnot read).main):test_airfoil_aero.jl134/134,test_yaml_geometry.jl182/182 (includestest_load_polar_data.jlandtest_wing_constructor.jl),test_obj_adapter.jl63/63,test_surfplan.jl8/8,test_wing_geometry.jl302/302.main(the CHANGELOG conflict kept both sides).Pkg.test(), Julia 1.13, fail-fast) on ce475fc: PASS in 5 min, exit 0 · GitHub CI on 0223e32 (merge ofmain, CHANGELOG only): PASS on every cell, Windows included. The Windows 1.12 cell failed once on ce475fc with the flaky ForwardDiff POLAR_MATRICES check (0.0571 < 1e-4, test_forwarddiff.jl:99), reopened as Flaky POLAR_MATRICES forwarddiff test on Windows / Julia 1.12 (knot-proximity in piecewise-linear polar interpolation) #360; this PR touches neither the solver nor that test ·jetls: not run, not installed on the box.read_node_tablereturns a view of the value columns (@allocated, second call).write_polar_csvor readinginfo["csv_file_path"]from a freshly written YAML; both are named in the CHANGELOG as breaking.Scope
+447 / −359 across 26 files against
main. About 80 of those lines are the key rename in thedata/andtest/YAMLs, one line each. Net growth sits insection_aero.jl(+45: the named-column reader split intoread_arrow_columns/read_csv_columns) and the tests.yaml_geometry.jlshrinks by 100 lines now thatload_polar_datareuses the reader, and the three polar writers shrink to a few lines each. Builds on #369, now merged. Closes #373.Closes #371 · task
VortexStepMethod.jl-371