Migrating to 0.23.0¶
This release changes the BYTES of every file the post stage writes, and renames some of them. Read this before you upgrade a workspace you care about.
You do not have to re-run anything. Every change below is produced by
pyfs-matrix post --workspace <root>
over outputs you already collected, on Windows and on the cluster. There is one exception and it is named in section 6.
1. No cell is ever blank again¶
A cell that does not apply to a row now reads NA.
before 9001,STEADY_WB,1,50.00000,2.52600,20.00000,9.15200,0.00000,0.00000,,-2.00000
after 9001,STEADY_WB,1,50.00000,2.52600,20.00000,9.15200,0.00000,0.00000,NA,-2.00000
A blank is ambiguous three ways: zero, not measured, or this column is not for this row. Measured on a production super file, 50 of 628 columns in one row were blank for the third reason alone.
If you read with pandas, nothing changes. Both '' and 'NA' are default
missing tokens for every column, so read_csv gave you NaN before and gives
you NaN now. Measured on pandas 3.0.5.
If you parse by hand, this is the change. The csv module gave you ""
and now gives you "NA". A reader that tested cell == "" must test for NA.
A reader that called float(cell) is unaffected: float("") raised before and
float("NA") raises now.
If NA is meaningful data in your own columns, pass keep_default_na=False
and name your own na_values.
One token, not two. The probes table's STEP column wrote - on a steady
row until this release and now writes NA like everything else. A reader
keying on - must change; one keying on NA already covers both.
One exception, named rather than left to be found. A run recorded before
0.16.0 names no probe-positions file, so that table's position and frame cells
are a value the package could not derive, and they read NA too. Refusing
those tables would take a product away from a campaign that already happened.
2. Every product says what it is a file OF¶
The product tables now carry the whole flight condition (ALPHA, BETA,
MACH, RE, VINF, ALT, J) and the reference lengths (SREF, CREF,
BREF): the polars, the unsteady polar, the rotor tables, the sections, the
probes and the reduction tables.
Not every file the post stage writes does. The plots table,
probes/<point>_plots.csv, carries the export's own columns and nothing else,
and the three point series under series/ carry step, time_s,
azimuth_deg and their export's columns. Read the condition of either from the
product beside it.
Before this release the sections, probes and reduction tables carried no
reference length at all, and the polar carried no VINF or ALT. A
coefficient beside no area is a number nobody can check, and a probe sample
with no condition is a table about nowhere.
What this means for your reader: these are NEW COLUMNS. A reader that selects columns by name is unaffected. A reader that assumes a column COUNT, or that reads by position, must be updated.
3. A polar group is NAMED, and your files are renamed for you¶
GROUPS takes one named input per group, and the product file carries that
name instead of _g01.
before P0001-M150AL+000BE+000J+sweep_g01.csv
after P0001-M150AL+000BE+000J+sweep_PUSHER.csv
Your existing products are moved, not orphaned:
from pyflightstream.workspace import rename_group_products
rename_group_products("<workspace root>", {1: "PUSHER", 2: "LIFT_L1"}, dry_run=True)
rename_group_products("<workspace root>", {1: "PUSHER", 2: "LIFT_L1"})
- You supply the mapping because nothing in a workspace records which group
_g03was. A number you do not give is LEFT ALONE, never renamed on a guess: a product renamed to the wrong group is worse than one not renamed at all. - Ask what you left out, before you migrate, which is while you can still act on it:
from pyflightstream.workspace import unmapped_group_numbers
unmapped_group_numbers("<workspace root>", {1: "PUSHER", 2: "LIFT_L1"})
# {3: [Path('.../P0001-M150_g03.csv')]}
A number you forgot is otherwise indistinguishable from a number that was
never there: you would see the products that moved and conclude you were done.
- It refuses before it moves anything. Every product is checked first and
moved second, so a refusal saying nothing was moved is true of the folder.
Two numbers you mapped to ONE name are refused too.
- It archives before it moves, and deletes nothing. A copy of each file
lands under archive/rename-groups-<stamp>/ first and stays there afterwards.
That is the default; archive=False moves without a copy.
- A destination that already exists is refused, naming both paths, with
nothing moved.
- Run it with dry_run=True first. It reports what would move and moves
nothing, and those records name no archive, because none was written.
4. _sections says which iteration and which azimuth¶
The POINT column carried the polar's NAME, which the file name already
carries. It is replaced by ITERATION and AZIMUTH, the two things that
actually vary down the table.
AZIMUTH reads NA on a run with no rotor, and never 0: zero is a real
azimuth a rotor row can hold.
5. A rotor now carries its INSTALLATION VECTOR¶
axis on a rotor block accepts a three-component vector as well as a letter:
[PUSHER]
kind = "rotor"
axis = [0.0, 0.199, 0.980] # a shaft with pitch and toe already in the mesh
Your existing references are untouched. A letter keeps its exact meaning --
Z IS (0, 0, 1) -- and a rotor stating a letter takes the same code path it
always did, so the script it emits is unchanged.
Two things change for a rotor that states a VECTOR:
- every frame the package builds for it is built on the shaft rather than on the geometry's axes;
- the blade datum is refused by ANGLE when it lies within five degrees of the
shaft. The old check compared two strings, so it caught
axis = Z, zero = Zand was blind to a shaft one degree from its datum, which reports an azimuth that locates nothing.
Not yet validated against a licensed run. No run with pitch and toe exists yet, so what is proved is that the letter path is unchanged and that a vector spelling of a letter gives the same script. Whether the frames a TILTED shaft produces match the hardware is owed to one licensed run at a known pitch.
6. The one thing post cannot give you¶
submitted_by in the provenance is a RUN-time fact. Nobody recorded it for the
simulations you already have, it cannot be recovered, and none is invented: for
those runs the field reads NA. It is filled from your next run onward.
7. The three pproc tables are NOT in this release¶
phase_locked, equations and glossary were planned for 0.23.0, were built,
and were withdrawn to 0.24.0 before the release. Do not write them.
# ALL THREE ARE REFUSED BY NAME in 0.23.0. A pproc carrying any of them
# does not load, and the message names the key.
[phase_locked] # refused
[equations.CTX] # refused
[glossary] # refused
They are refused rather than ignored, and that is deliberate. A key the release does not support must fail on the key: a pproc that is accepted and then quietly does nothing is the worse of the two failures, because you would read the products as though the reduction had run.
This section used to show you how to write all three, and it contradicted the Not in this release section at the foot of this same page. A page that teaches a key the package refuses is worse than a page that omits it, so this is the correction rather than a deletion: if you wrote one of these tables on the strength of the old text, the refusal you saw was the package being right.
Nothing you write today is lost. The code behind all three is still in the tree; what was withdrawn is the ability to ASK for it, and 0.24.0 resumes from there.
8. Everything else that moved¶
- A rotor table carries
J,CT,CQ,CP,ETA,ETAWper rotor, each suffixed with the rotor's alias.
ON A STATIC POINT EVERY ONE OF THEM READS NA EXCEPT J. This page said
CT and CQ were still written; a V&V round proved that false at every
caller and the change log was corrected without this page following. The
reason is the export rather than the package: it states coefficients
normalised by the run's own dynamic pressure, which is zero at rest, so a
hovering rotor's real thrust has been divided away before any of this is
computed. J is a real 0.00000 -- at rest with a turning rotor the advance
ratio genuinely is zero.
- The rotor table names its alias on its first line, alone, so a script
that has loaded the file still knows which group it holds.
The averaging window moves to the matrix row¶
State it once, on the row, beside the clock that gives it a length.
| column | run type | unit |
|---|---|---|
LAST_REVS_AVG |
unsteady_rotor |
last revolutions, accepts a float |
LAST_ITERS_AVG |
unsteady |
last iterations |
Write the key in UPPER CASE, exactly as above. A key of VAR_NAMES_VALUES
is matched on its exact spelling, so last_revs_avg in lower case is refused
on a workflow row as a key of no run type, and is not read at all where that
check does not run.
It is the window the POLAR, the time average and per_blade all use. On a row
turning several rotors, LAST_REVS_AVG is a COUNT of revolutions: each rotor
converts it with its own revolution length, so a lifter and a pusher get
different spans from the same key and neither has the other's turn imposed on
it.
WINDOW_STEPS, WINDOW_REVOLUTIONS and WINDOW_DEGREES are deprecated,
due for removal at 0.26.0. A row stating one still binds and now WARNS, naming
the replacement. Degrees are revolutions over 360, so WINDOW_DEGREES = 90 is
LAST_REVS_AVG: 0.25. A row stating both an old key and a new one gets the new
one.
An unsteady point's POLAR changes shape, and so does its folder¶
This is the migration fact most likely to surprise you, so it is stated before the reasoning.
An unsteady simulation used to write one polar per pproc group under
polars/<sim>_<sweep>_<group>.csv, plus the super file and, where asked, the
fixed-width .dat. It now writes one table per simulation instead:
polars/<sim>_<sweep>_unsteady.csv
one row per point, and the group polars, the super file and the .dat are not
written for that point. Nothing is silently dropped: a simulation whose points
exported no plots records a skip naming the file.
Its columns are the plot variables under the names the export prints them,
not the twenty-four fixed coefficients of the steady polar. Nothing in this
package knows which plot label carries which coefficient, and a label the
package invented would not fail loudly -- it would write NA down a whole
column. A dictionary that maps the names is 0.24.0 scope.
Why it changed: by the definition of record, the native coefficient export states the LAST TIME STEP only. On an oscillating rotor that is one instant of a cycle. The native export still ships, as a health check.
What judges an unsteady point did NOT change. This page said the run assessor judges an unsteady point from the plots history. It does not: the former plot-history helper had no caller on the run or collect path and was removed in 0.26.0. An unsteady point is judged in 0.23.0 exactly as in 0.22.0, by the standard loads assessor, from the collected loads table and, where one was exported, the solver log. A history that diverged and ended on a finite step is therefore NOT caught by this release, and whether the history has settled is never the package's judgement: see what the package does not judge.
Not in this release¶
Listed because an absence you discover is worse than one you are told:
- the super file in the fixed-width
legacy_polarformat, per_bladeas one row per blade with the azimuths in columns,- the
[phase_locked]pproc table, - the
[equations]table and its[glossary], - the generated
VARIABLES.mdandWRITING-EQUATIONS.md.
0.23.0 adds no pproc table at all, so a pproc written for 0.22.0 binds unchanged. Those three table names are refused BY NAME rather than accepted and ignored: a refusal says the feature is not here, where silent acceptance would let you write the table and get nothing back.