Conversation
…_user hook
CalculiX has two external hooks and they do not share a convention.
call_external_umat is reached from umat_abaqus.f after that wrapper has already
converted to the Abaqus UMAT convention, so NUMSIM_MATERIALS_DEFINE_UMAT already
serves it. call_external_umat_user is the native hook, and this adapter
translates its conventions onto umat_dispatch:
- kode carries the constant count as -100 - nconst;
- emec/emec0 are TENSORIAL, so the shear is doubled to the engineering form
the dispatch buffer expects, exactly as umat_abaqus.f:280-283 does;
- xstateini/xstate are the FULL (nstate_, mi(1), #elements) arrays, not a
slice, so state is indexed at nstatv*((iint-1) + mi1*(iel-1));
- TIME is rebased onto the start of the increment per umat_abaqus.f:187-188;
- the 6x6 tangent is symmetrized into stiff(21) as umat_abaqus.f:335-355 does,
reading the column-major buffer narrow_matrix writes.
A local orientation and a nonzero initial stress are refused rather than
silently ignored: the native hook makes frame rotation the material's own
responsibility, so returning unrotated results would be wrong with no symptom.
Scope is geometrically linear; the PK2/Green-Lagrange pairing is exact only for
a linear C:E law.
REVIEW.md records the three-lens review this came out of, including the three
silent-wrong-answer bugs it found. Each has a regression test verified to fail
against the pre-fix code.
Four gaps found by re-reviewing this branch against the real ccx 2.22 source. The conversions themselves held up -- all eight rows of the table, the 31-arg ABI, the stiff(21) packing and the TIME rebasing were re-derived from the Fortran and are correct -- so these are the edges. ielas is now refused rather than ignored. ielas = 1 asks for a response with no irreversible deformation; arpack.c, arpackbu.c and arpackcs.c all set it, which is every *BUCKLE and *FREQUENCY step. Nothing here can suppress plastic flow on request, so answering anyway folds irreversible effects into the tangent and skews the extracted eigenvalues with no symptom. It joins iorien and beta in the refuse-rather-than-guess group. The emec/emec0 null guard had no test. REVIEW.md's resolution table listed M6 as fixed, and deleting the guard left all eleven tests passing -- a claim, not a behaviour. With the new test the binary segfaults instead, which is the guard's whole point. A fatal tripped outside a FatalProbe aborted the entire test binary. The default handler calls std::abort(), which is right in a solver -- returning would hand the host a silently wrong material response -- and wrong in a test run, where it masks every other result. Mutating the kode decode by one was enough to lose the whole suite to a SIGABRT. A binary-wide handler now fails the current test instead; verified by mutation to give exit 1 with the other 15 tests still running. FatalProbe restores that handler rather than the library default, so the first probe in a run no longer re-arms abort() for everything after it. The header said nothing about how the .so is found. ccx prepends "lib", appends ".so" and dlsyms FUNC verbatim, which is why FUNC carries no trailing underscore here while the Abaqus entry point is umat_ -- get it backwards and it fails at run time with "unable to load function" and nothing at build time. Also recorded: the symbol must stay exported (-fvisibility=hidden hides it with no other symptom), and ccx builds the library name into a fixed char b[80] with an unchecked memcpy, so the LIB name must be short. Two tests written during the review are ported in, closing the last two items REVIEW.md listed as still open: a throwing material proves PNEWDT = 0.25 lands on the CALLER's buffer for a cutback, and eight threads driving the entry point at distinct (iel, iint) must agree with the same sequences run serially. Every one of the four is mutation-verified: removing the ielas guard, the null guard, the pnewdt forwarding, or the isolation handler each fails exactly its own test. 16/16 pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the
.soentry point CalculiXdlopens for*MATERIAL, NAME=@LIB,FUNC, translating CalculiX's nativecall_external_umat_userconventions onto the existingumat_dispatch.Why a second entry point
CalculiX has two external hooks and they do not share a convention:
call_external_umatis reached fromumat_abaqus.fafter that wrapper has already converted to the Abaqus UMAT convention.NUMSIM_MATERIALS_DEFINE_UMATalready serves it — no adapter needed.call_external_umat_useris the native hook. It speaks CalculiX's own conventions, which this adapter translates.What the adapter translates
kode = -100 - nconstnprops = -kode - 100emec/emec0{11,22,33,12,13,23}, end/startSTRAN=emec0,DSTRAN=emec-emec0strestiff(21)stiff[i+j*(j+1)/2]xstateini/xstate(nstate_, mi(1), #elem)arraysnstatv*((iint-1) + mi1*(iel-1))TIMEEach conversion mirrors CalculiX's own reference wrapper
umat_abaqus.f(shear doubling at:280-283, TIME at:187-188, stiff packing at:335-355).Guards rather than silent omissions
iorien != 0and a nonzerobetaare refused, not ignored. The native hook makes frame rotation the material's own responsibility (umat_user.f:86-104) — unlike the Abaqus path, where ccx rotates around the call — so ignoring either would return wrong results with no symptom.Scope is documented as geometrically linear: the PK2/Green-Lagrange pairing is exact only for a linear
C:Elaw.Review
REVIEW.mdrecords the three-lens review this came out of. It found three bugs that would each have produced a silently wrong result:TIMEshort by(time - dtime)on every increment after the first.Every Critical/High finding was re-verified against the CalculiX 2.22 source — one reviewer's "the packing is correct" was itself wrong. Each of the three has a regression test that was verified to fail against the pre-fix code before the fix was restored, so none is vacuous.
Testing
11 new tests; 291/291 pass on this branch, clean build, no warnings. Coverage includes a 40-increment J2 run at
iel=2, iint=3(asserting no other state block is touched), asymmetric-tangent packing, exact TIME values via a probe material, nonzero start strain, and four error paths.Not covered
ccxthrough the@LIB,FUNCdeck path yet.PNEWDTcutback test (the path is inherited unchanged fromumat_dispatch).ielas == 1is accepted and ignored; harmless for elastic, an inelastic model will need to honour it.