Projection onto a symmetry class
Given an arbitrary tensor, find the closest one having a prescribed material symmetry — and, if the orientation is unknown, find that too. This page states the problem, derives the closed forms TensND uses at fixed orientation, and describes the optimizer used when the orientation is free.
Implementation: src/tens_projection.jl and, for the orientation search, the weak-dependency extension ext/TensNDNLoptExt.jl. The formulation follows the one of the Echoes C++ library; the general theory of closest tensors of prescribed symmetry is [10], and the harmonic-decomposition alternative is [11].
The problem
Let
so proj_tens returns the triple
| Returned | Meaning |
|---|---|
| the projected tensor, in the storage type of the class | |
| absolute distance | |
| relative distance |
Because the Kelvin–Mandel map is an isometry (Kelvin–Mandel representation), the whole computation is done on
Fixed orientation: the normal equations
Write a basis
In general this is an TensND never performs one is that in the bases it uses, the Gram matrix is diagonal.
Transverse isotropy
The major-symmetric TI subspace is spanned by the symmetrized Walpole basis ``\mathbb{W}^s=(\mathbb{W}_1,\ \mathbb{W}_2,\ \mathbb{W}_3+\mathbb{W}_4, MarkdownAST.LineBreak()
\mathbb{W}_5,\ \mathbb{W}_6)``, whose Gram matrix is (The Walpole basis)
Each coefficient is therefore an independent quotient,
gives the closed forms implemented in _project_TI_KM:
Every one of them is a plain average of the entries the corresponding
Orthotropy
Same argument with the nine orthotropic generators, which are likewise mutually orthogonal. The projection at fixed frame simply keeps the block-diagonal part and symmetrizes (_project_ORTHO_KM):
everything outside the two blocks being discarded. For an order-2 tensor the same reasoning reduces to keep the diagonal in the material frame.
Cubic symmetry
The cleanest case of all, because the three generators are not merely mutually orthogonal but are projectors summing to the identity. The normal equations degenerate into three traces (_project_CUBIC_KM):
the divisors being the traces of the projectors themselves. Concretely,
At order 2 there is nothing to do: the octahedral group leaves no second-order tensor invariant but a multiple of the identity, so the cubic projection is the isotropic one. See Cubic symmetry.
With a free orientation the treatment is the orthotropic one unchanged: the cube orientation is an ordinary rotation, so the objective
Isotropy
The two-dimensional case, already given in Isotropic tensors:
Free orientation
When the axis or frame is unknown,
with
Condensing out the linear part
For a given
This is literally what _obj_TI4 and _obj_ORTHO4 compute: rotate, project, compare norms. Maximizing the norm of the projection is minimizing the distance, and only two or three angles remain —
Differentiating the normal equations shows that the gradient needs no derivative of
In practice TensND obtains this gradient by automatic differentiation (ForwardDiff through the objective), which is exact to machine precision and removes any risk of the analytic expression drifting from the code.
The optimizer
Loading NLopt activates TensNDNLoptExt and enables the no-orientation methods of proj_tens. The strategy is a deterministic multi-start:
a candidate from the eigenstructure of
(_candidate_TI_axis,_candidate_ORTHO_frame,_candidate_CUBIC_frame) — exact whenever the tensor genuinely has the symmetry sought;a fixed angular grid containing the canonical axes;
LD_TNEWTONlocal refinement from every start, with ForwardDiff gradients;the best objective over all starts and all refined starts.
Two properties follow, and both matter:
reproducibility — repeated calls return bit-identical angles;
no regression — because the grid contains the canonical frame, the optimized projection is never worse than the fixed-frame projection along any grid point.
Why the stochastic global pass was removed
Earlier versions followed the Echoes C++ strategy: a GD_MLSL global stage followed by a local one. GD_MLSL is stochastic and NLopt seeds it from the clock, so results were irreproducible from call to call. On a tensor exactly orthotropic about a tilted frame, roughly 0.5 % of runs returned a spurious local minimum (GD_MLSL runs on every tensor tested — 150 random anisotropic ones included — and is 3 to 8 times faster.
Detecting the symmetry: the cascade
best_sym_tens tries the classes from the most restrictive to the least and returns the first whose relative error falls below a tolerance
The chain is ordered by number of constants — 2, 3, 5, 9 — and not by inclusion, because it cannot be:
The relative criterion is what makes the tolerance dimensionless and independent of the units of the moduli. Two modes:
optimize_angles | TI axis / ORTHO frame / CUBIC frame | Needs NLopt |
|---|---|---|
false (default) | taken from the tensor if it is a structured container, otherwise from the Kelvin–Mandel eigenstructure | no |
true | found by the multi-start above | yes |
The value-level predicates is_ISO, is_TI, is_ORTHO, is_CUBIC are the same computation with a boolean answer.
Projection is not averaging
Two different operations are easily confused, and only one of them is on this page.
| Projection (this page) | Group average | |
|---|---|---|
| definition | closest element of the subspace | |
| result | best fit in the class | exact invariant part |
| target space | major-symmetric subspace (5 or 9 parameters) | full commutant (8 parameters for TI) |
| discards | everything orthogonal to the subspace | nothing invariant |
For a major-symmetric input the two coincide. For an input that is not major-symmetric — a strain-concentration tensor, typically — they differ: the average preserves the
The choice of distance
Everything above minimizes the Euclidean (Frobenius) distance. That choice is not neutral: it is not invariant under inversion, so projecting a stiffness and projecting its compliance give different materials (Isotropic tensors). Distances that repair this — log-Euclidean, power-Euclidean, arctan-Euclidean — are constructed in [5]. TensND implements the Euclidean one only, so a reported projection should always state which of