Skip to content

History kinds: kinded<T, voigt, leg...> for rotation and STATEV storage - #224

Open
petlenz wants to merge 1 commit into
mainfrom
feature/issue-216
Open

petlenz wants to merge 1 commit into
mainfrom
feature/issue-216

Conversation

@petlenz

@petlenz petlenz commented Oct 28, 2026

Copy link
Copy Markdown
Member

Implements #216 (part of epic #221). No other PR has to merge first.

What and why

statev_map knew three history shapes: a scalar, a symmetric rank-2 tensor stored like a strain (plus stress_like from #91), and a minor-symmetric rank-4 tensor. Every tensor entry was rotated under DROT. Reference-configuration history (Cp, Fp, a fibre structure tensor), non-symmetric tensors, vectors and symmetric non-strains (conductivity, diffusivity) had no correct storage.

This PR generalises stress_like into a kind carried by the type:

  • core/tensor_kind.h (new): enum class leg {spatial, material}, enum class voigt {none, engineering, plain} and kinded<T, V, Legs...>, a tmech::tensor<T, 3, sizeof...(Legs)> with the tensor's constructors, assignment and expression support. Aliases: stress_like, reference_strain, two_point, material_tensor, spatial_vector, material_vector, spatial_moduli, material_moduli.
  • rotated(a, R) / rotate_legs<Legs...>(t, R): R acts on each spatial leg only, so R·v, R·t·Rᵀ, R·t, t·Rᵀ, or nothing.
  • core/stress_like.h stays as a header that includes tensor_kind.h, so existing includes keep compiling.
  • umat/statev_map.h: one entry builder (add_kinded<V, Legs...>) for every kinded type and for plain tensor<T,3,2>:
    • width 3 or 9 for voigt::none (all components, row-major), 6 otherwise (Abaqus order, shear doubled for engineering and as is for plain);
    • require_symmetric on pack for engineering/plain, no check for none;
    • a rotate step only if some leg is spatial, so has_rotatable_history() is false when only material-leg and scalar history exist, and the UMAT evaluator then skips the DROT step;
    • describe() marks each entry with its storage and legs: [engineering shear], [stress], [vector], [full], then [reference] (all legs material) or [two-point] (mixed legs).
    • The separate stress_like branch from STATEV: stress-like tensor history without the engineering-shear factor (#63) #91 is gone; stress_like goes through the same builder.
  • umat/tensor_conversion.h: full_from_buffer / full_to_buffer (tmech full<3> adaptor) next to the strain/stress conversions.

A plain tensor<T,3,2> history keeps its meaning (engineering shear, spatial legs), and scalars and tensor<T,3,4> are unchanged. No existing material changes its STATEV layout.

Decisions

  • stress_like was stress_like<T, Dim = 3>; it is now the alias stress_like<T> from the issue, because kinded is 3D only. Every user in the repository writes stress_like<value_type>.
  • spatial_moduli and stress_like are the same type, as in the issue's sketch, so a spatial modulus is described as [stress] (stored without the shear factor).
  • kinded rejects at compile time the combinations that cannot be stored: rank other than 1 or 2, a vector with six-slot storage, and six-slot storage of a two-point tensor (symmetry needs both legs alike).
  • The full 9-slot layout is row-major {11 12 13 21 22 23 31 32 33}, the tmech full<3> adaptor.
  • Rank-4 history keeps its own branch (all four legs spatial). No kind for it is needed yet.
  • material_point / material_point_evaluator needed no change: they already ask has_rotatable_history() before the DROT step.

Tests

New tests/test_history_kinds.cpp (9 tests), with two test-only probe materials whose history outputs are kinded:

  • stress_like<T> is kinded<T, plain, spatial, spatial>; rotated() acts on each spatial leg only (vector, symmetric, two-point either way round, material).
  • With a 30° DROT, reference_strain, material_vector and material_tensor come back unchanged on both sides, while tensor2, spatial_vector, spatial_moduli rotate and two_point becomes R·F.
  • two_point and material_tensor keep all 9 non-symmetric components through pack and unpack (raw slots checked); vectors round-trip through 3 slots.
  • spatial_moduli stores D₁₂ while the tensor2 and reference_strain next to it store 2ε₁₂.
  • reference_strain with a skew part is rejected on pack.
  • Widths and describe() marks for every kind.
  • has_rotatable_history() is false with only material-leg and scalar history.
  • STATEV: stress-like tensor history without the engineering-shear factor (#63) #91's StatevMap.StressLikeHistoryKeepsItsShearComponentsForTheHost and all existing statev_map tests pass unchanged.

Gate

GCC 14 gate (with the ASan/UBSan test targets, -Werror): BUILD=0, 1458/1458 tests passed, 0 warnings.

core/tensor_kind.h grows stress_like into kinded<T, voigt, leg...> with the
aliases for reference strains, two-point and material tensors, vectors and
moduli, and rotated() acting on spatial legs only. statev_map builds every
kinded entry with one builder: 3/9 full slots for voigt::none, 6 otherwise,
a rotate step only when a leg is spatial, and describe() marks per kind.
Plain tensor2 history keeps its engineering, spatial meaning.
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