Repository navigation
Conversation
PR Review👋 I checked your PR and found no issues. Thanks!
|
🚀 Profiling Results (Top 20 most expensive calls)
|
|
Correction to the test evidence in the description above. It says the suite shows "only the pre-existing environmental failures". That was wrong, and the error was mine: I ran the test suite with Run correctly (the environment's
So the baseline is zero failures, not eight or twelve, and this branch adds none. The comparisons in the description remain valid — clean 🤖 Generated with Claude Code |
Abaqus' *Tie data line is `secondary, main`. The reader put the FIRST surface into `m_set` and the writer wrote `m_set, s_set` back out, so the two mistakes cancelled: the Abaqus round trip agreed with itself while both ends were wrong, and no test could see it. Every other consumer of the constraint could: the Sesam writer's `coupling_records` and `shell2solid_records` both take `m_set` for the independent side, so a tie converted on that basis came out with the dependent and independent sides exchanged -- a model that still runs, still analyses, and is wrong. The convention (`m_set` independent, `s_set` dependent, for every constraint type) is now written down where the constraints are read, and pinned by a test from the deck through to the BLDEP records rather than by a round trip, which a pair of mirrored mistakes passes. Alongside, three things the reader did to a constraint quietly: * a *Coupling followed by *Distributing (three spellings) matched nothing and the whole constraint left the model on a log line. It is read now, which sub-keyword it was is kept, the Abaqus writer puts the same one back, and the Sesam writer says that a distributing coupling became rigid links instead of writing one as the other. * a *Kinematic data line of one DOF raised ValueError out of reshape(-1, 2) and took the import down; an empty one is all six DOFs, and says so. * *Tie's `tied nset` and `cyclic symmetry` narrow which secondary nodes are constrained, nothing acts on either, and every writer ties the whole region. Reported per tie. And *System is applied: it is not a construct that goes missing, it MOVES THE MESH. Nodes under `*System 0., -660., 0.` were read at the origin. The keyword census could say *SYSTEM went unread; it could not say the nodes were in the wrong place. The 6-number off-axis case leaves the local Y and Z axes undetermined and is reported rather than guessed at. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv
… of the census test The *System tests only reached get_nodes_from_inp_arrays, so removing the transform from get_nodes_from_inp left all twelve of them passing. Both readers are now driven directly, with an assertion that they agree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv
…t keep SLIDER takes three nodes; a Constraint holds one node pair, so the third was dropped in silence -- the constraint that came out was not the one the deck wrote, with only the two nodes it kept to show for it. It is reported now, per block, with the count and the types. Also narrows the constraint-sides note to the types it is actually true of. *MPC has the same inversion *Tie had -- Abaqus eliminates the FIRST node of a data line, and the reader puts it in m_set -- but it is latent: no writer reads an MPC's sides as independent/dependent, and flipping it would also flip what convert_ecc_to_mpc writes for every beam offset, which of its two nodes it means to eliminate being established nowhere. Named rather than changed blind. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv
…t lands on
A tie was left out of the Sesam deck altogether: `a "tie" constraint has no Sesam form`.
It has one. Abaqus ties a secondary surface to a main surface by projecting each secondary
node onto the main surface and interpolating between the nodes of the FACET it lands on,
and Sesam can say exactly that -- several BLDEP records may name the same dependent node
with different independent nodes and Sesam sums them (manual 7.2.14). So one record is
written per facet node, carrying the facet's shape-function weight at the projected point
times the rigid arm to that node. The weights sum to 1, which is what makes a rigid-body
motion of the main surface pass through exactly.
The rigid arm to the nearest main *node* -- what this module does for shell-to-solid
coupling -- is not where Abaqus ties: 16.7 mm out on average on the acceptance deck, of
the order of half a plate element. It stays as the fallback for a main surface with no
facets to project onto (a NODE surface, a plain node set), which is then reported as the
approximation it is, with its distance distribution.
Two consequences of having facets at all:
* `position tolerance` can finally be compared with what it means -- a distance to the
main SURFACE. The nearest-node path still needs a node-spacing slack to make the units
of its comparison agree, and that slack cannot tell a 20 mm in-plane offset from a
20 mm gap.
* `ada.fem.surfaces` grows `surface_facets`, sharing one reading of a region with
`surface_nodes` so the two cannot disagree about what a surface covers.
And the free-face rule: `ELSET,` -- an element surface entry naming no face identifier --
is valid Abaqus and means, for a continuum element, its FREE faces. It reached
`int("") - 1` and took the whole *Surface down with a bare ValueError. Read as the blank
side, resolved to the free faces from the elements' own node back-references (23 ms on a
460,738-element deck, against 8.6 s to hash every solid face of the mesh), and reported as
suspect where they cannot be determined rather than silently taken as every node of the
element -- which reaches into the interior of the body.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv
The reader tests pin the reader, test_write_tie pins the writer against hand-built constraints, and the defect lived in the join between them: the reader put the deck's first surface into m_set and the writer takes m_set for the independent side. This reads a deck and asserts on the BLDEP records -- the dependent nodes are the ones the deck named first -- and, because the main surface is element-based, that a dependent node reaches the four nodes of the facet it projects onto with weights summing to 1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv
6fa2236 to
dc1a005
Compare
|
Folded into #407. This branch was merged in as-is, with its own merge commit, so every commit and its authorship #407 collects the six format-level FEA PRs (#394, #395, #396, #399, #400, #404) into one, since |
…nd verify plates through decks (#407) Folds the six format-level FEA PRs into one, drops the Abaqus/CAE stack, and gives the verification report a plate case built through the deck writers. Folded: #394 (*Tie -> BLDEP facet interpolation), #395 (Sesam super element number), #396 (a symmetric section's zero product of inertia), #399 (.gnx as a first-class format), #400 (Sesam settlement, one BLDEP term per dof pair, instance-qualified *MPC), #404 (surface pressure as BEUSLO). Dropped: #398, #401, #402, #403, #405 -- src/ada/cadit/cae, Part.to_abaqus_cae_script, its tests and verification/genie_vs_abaqus, which drives `abaqus cae noGUI=`. adapy supports formats, not APIs into proprietary software, and a verification entry only a CAE licence can reproduce verifies nothing anyone can check. Salvaged from it, because it is format-level: a T-profile now reaches an Abaqus *Beam Section as section=I with the bottom flange zeroed (it had no mapping at all), and Calculix converts a T to a general section as it already did an I. New: the plate strip case -- an ada.Plate meshed by the meshing module (gmsh), written as a deck per solver, checked against 5 q L^4 / (384 D) and f_n = n^2 pi / (2 L^2) sqrt(D / (rho t)). Code_Aster lands on the eigen closed form to six digits. Writer gaps it exposed, each found by running it rather than reading: * Calculix had no pressure load at all; it now writes *DLOAD ... P. Measured on ccx 2.23 that P, P1 and P2 are bit-identical on a shell, so the label carries no face and only the sign can. * Code_Aster's pressure had never run: FORCE_FACE with FY is a traction along global Y, not a normal pressure, and GROUP_MA named the surface, which has no MED counterpart -- every attempt stopped at <EXCEPTION> <MODELISA7_77>. Now FORCE_COQUE=_F(PRES=...) over the element sets, via the new shared ada.fem.surfaces.pressure_elsets. * Code_Aster refused any eigenvalue analysis with more than one Bc; ASSEMBLAGE's CHARGE takes a tuple. * The Sesam BEUSLO pressure sign was inverted relative to Abaqus, Calculix and Code_Aster. The reference it was tuned against applied its load along global -z on the grounds that -z was "against the plate's +z normal"; the strip's element normals are all -z (measured, all 128), so the reference ran along the normal and the test that pinned it never checked which face was named. Code_Aster reproduces the Sestra magnitude to eight digits with the opposite sign. The measured Sestra numbers are kept exactly as measured; only which face they belong to changed. The Sestra leg runs only where Sestra is installed, so a licensed re-run remains the confirmation worth having. Co-Authored-By: oleandor <oleandor@gmail.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXGBkUbGK6oYWxm5R2WYVB
A
*Tieis not a rigid arm to the nearest nodeAbaqus ties a secondary surface to a main surface by projecting each secondary node onto the main
surface and interpolating between the nodes of the facet it lands on. The rigid arm to the
nearest main node — which is what this writer does for a shell-to-solid coupling — is off by
16.7 mm on average on the acceptance deck, of the order of half a plate element, and no measure
can turn it into the right answer because the nearest node of a facet is simply not where Abaqus
ties.
Sesam can express the real thing. Several BLDEP records may name the same dependent node with
different independent nodes and Sesam sums them (manual §7.2.14), so one record is written per
facet node, each carrying that facet's shape-function weight at the projected point times the rigid
arm to that node:
The weights sum to 1, and that is the load-bearing property: it is what makes any rigid-body motion
of the main surface pass through exactly, whatever the weights happen to be. Where the main
surface has no rotational DOFs (a solid mesh) the relation reduces to
u_slave = sum_k w_k u_k,which is Abaqus' tie constraint term for term. It is asserted on the records, not taken on trust.
Two consequences of having facets at all:
position tolerancecan finally be compared with what it means — a distance to the mainsurface. The nearest-node path needs a node-spacing slack purely to make the units of its
comparison agree, and that slack cannot tell a 20 mm in-plane offset from a 20 mm gap.
ada.fem.surfacesgrowssurface_facets, which shares one reading of a region withsurface_nodes, so the two cannot disagree about what a surface covers. The cutoff and the nodeset now come from the same reading; they did not.
adjustis reported, not honoured: it tells Abaqus to move secondary nodes, ada never moves nodes,and holding a node rigidly off the facet is exact for rigid-body motion. Treating
adjust=yesas aninfinite tolerance would tie nodes Abaqus leaves free.
Where a main surface offers no facet — a
NODE-type surface, a plain node set, or (rarer) facettopologies this writer has no shape functions for — the nearest-node arm is used and reported as the
approximation it is, with its distance distribution, and the finding says which of those two ways
it got there.
The free-face rule
ELSET,— an element surface entry naming no face identifier — is valid Abaqus, and for a continuumelement it means that element's free faces. It reached
int("") - 1and took the whole*Surfacedown with a bareValueError; an entry written without the trailing comma at all arrivedas the float
1.0and raisedAttributeError.It is read now as the blank side — which is not the same thing as no side — and resolved to the
free faces. Adjacency comes off the elements' own
Node._refsback-references rather than amesh-wide face table: 23 ms on the user's 460,738-element deck for the 132-element entry that
motivated this, against 8.6 s to hash all 946,021 solid faces; both agree on all 132 free faces.
Where the free faces genuinely cannot be determined (
Node._refsnot carrying the elements, or aneighbour with no Abaqus face numbering) the answer is a
suspectfinding, not a guess — takingthe whole element instead pulls in nodes on faces interior to the body, which are on no surface at
all. The Abaqus writer round-trips the blank side rather than inventing a face number for it.
Evidence
tests/core: 0 failed. Clean 0.91.0 is 4265 passed / 0 failed.md5
dab3c17db89e10a65a0a808ddd7dab92), the whole 344 MB file is identical but for the timestampline. That deck has no
*Tieand no side-less surface entry, so this adds nothing to it — which isthe point of checking.
dropping the shape-function weight from the arm (caught by the rigid-body-motion test), keeping a
zero weight, reading a side-less entry as the whole element, and calling a face free without
looking at its neighbours.
One thing left on the table
bldep_records's_mergedfolds records sharing a(slave, master)pair by concatenating theirterms. If two constraints declare the same
(slave_dof, master_dof)on the same pair, Sesam sums thetwo coefficients — so the pair is written once, as the manual requires, but with a doubled
dependency. That is #386's merge, not new here, and
bldep_recordsalready raises asuspectwhentwo constraints claim one dependent DOF. Worth a follow-up that drops the repeated term and says
so, rather than folding it in.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Nej3bWxJevs9GkH6tg1WKv