Repository navigation
Conversation
A return map that reaches the solver through a material_ref and solves only when the trial state yields (docs/plasticity.md, section 9) needs two things the solver did not offer: - graph_driven (default true). false leaves the unknowns without an update callback, so ctx.update() no longer runs a cold-start solve at every point, elastic ones included, where the yield residual has a negative root. - reset(): zero the unknowns and mark not converged. The function material's residual callback is still a property the engine fires once per update, at whatever the slots hold; on an elastic step zero is the local solution and a stale dl from the previous point must not be read as this point's. Existing behaviour is unchanged: all 29 vector_newton tests pass as before.
…newton (#162) The first shipped material on the coupled solver. Unknowns {dlambda, dbeta} with dbeta = beta - beta_n, so the zero seed is the trial state: R_l = q - 3G dl - sigma_0 - H(kappa_n + dl) R_b = (1 + gamma dl) beta - beta_n - (2/3) C dl N gamma = 0 is Prager: radial in the shifted space, closed form, one Newton step. gamma > 0 rotates the flow direction during the step and the solve iterates. The consistent tangent comes through the solver's strain_derivative opt-in. The solver is held by material_ref and run only when the trial state yields; it must be created with graph_driven = false (checked) and the elastic branch calls reset(), because the engine fires the residual callback once per update and it writes kappa_n + dl into the history the hardening source reads. Tests: Prager closed form on a step with a committed, non-parallel beta_n; Prager converges with max_iter = 1 while Armstrong-Frederick throws; shifted surface and evolution law for gamma > 0; elastic steps leave history and unknowns clean; graph-driven solver rejected; Jacobian blocks and consistent tangent against directional central differences; Bauschinger reverse limit. Seven mutations of the material each fail at least one of them. Registered as j2_kinematic_plasticity; documented in plasticity.md and README. The back stress stays a plain tensor2 history until #91 lands.
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.
Closes #162. Kinematic half of #20.
What
materials/j2_kinematic_plasticity.h— J2 with Armstrong-Frederick kinematic hardening on top of the existing isotropichardening_source, returned as one coupled system over{Δλ, Δβ}byvector_newton. The first shipped material on the coupled solver.With
s_tr = 2G dev(ε − ε_p,n),η = s_tr − dev(β),q = σ_eq(η),N = (3/2) η/q:Jacobian and the partial strain derivatives are derived (see the header). The consistent tangent comes through the solver's
strain_derivativeopt-in (#19) and the chain ruledσ/dε = C_e − 2G [N ⊗ dΔλ/dε + Δλ dN/dε].γ = 0is Prager: radial in the shifted space, closed formΔλ = (q_tr − σ_0 − H_n)/(3G + C + H'), one Newton step from the trial seed.γ > 0rotates the flow direction during the step and the solve iterates. The tensor unknown is the incrementΔβ, so the solver's zero seed is the trial state; withβitself as the unknown even Prager needed several steps onceβ_n ≠ 0.vector_newton— two small additions the material needs:graph_driven(bool, defaulttrue).falseleaves the unknowns without an update callback, so the solver runs only when a material callssolve()through amaterial_ref. This is the design plasticity.md §9 settled on forlocal_newton, applied here: a graph-driven solver would also run a cold-start solve at every point, elastic ones included, where the yield residual has a negative root. The material checks the flag and throws.reset(): zero the unknowns, mark not converged. The material's residual callback is still a property the engine fires once per update, at whatever the solver's slots hold, and it writesκ_n + Δλinto the history the hardening source reads. On an elastic step the previous point's convergedΔλwould otherwise be added to this point'sκ. Found by the Bauschinger test below; the elastic test now pins it.Registered as
j2_kinematic_plasticity; the conformance tests pick it up. Documented in plasticity.md (§2 interface, §9 the solver decision) and the README.Tests (
tests/test_j2_kinematic_plasticity.cpp, 8)PragerStepMatchesTheClosedFormΔλ,β,κand the shifted yield condition against the closed form, on a second step whose committedβ_nis not parallel to the trial deviatorOnlyRecoveryNeedsMoreThanOneNewtonStepmax_iter = 1on that step; Armstrong-Frederick throwsRecoveryReturnsOnTheShiftedSurfaceAndRotatesTheFlowγ > 0: shifted surface, evolution law met by the finalN, flow direction rotated away fromη_trAnElasticStepDoesNotRunTheSolverκ,βand the unknowns cleanRejectsAGraphDrivenSolvergraph_driven = trueconfiguration throwsJacobianMatchesDirectionalFiniteDifferencesTangentMatchesDirectionalFiniteDifferencesOfTheStressγ = 0andγ = 40, non-proportional committed historyReverseYieldIsShiftedByTheBackStressβ_12 − Y/√3, probed from both sidesDirectional finite differences rather than component loops: the Mandel space the solver works in sees
IIsymas the identity, so perturbing one off-diagonal component alone compares against the wrong object.Mutations, each caught:
dR_β/dεsignJ_βλdropsγ βJ_ββcoupling1.5 → 2Δλ dN/dεdβ/dεβ_ninstead ofβreset()on the elastic branchNot in this PR
back_stressasstress_like(STATEV: stress-like tensor history without the engineering-shear factor (#63) #91 / STATEV layout applies the engineering-shear factor to every symmetric tensor, which mis-scales stress-like history #63): the history is a plaintensor2, sostatev_mapexports it with the strain shear factor. Noted in the header and the docs.