@@ -22,6 +22,24 @@ function material_routine(material_model::AbstractMaterialModel, F::Tensor{2}, c
2222 return P, ∂P∂F + ∂P∂QdQdF
2323end
2424
25+ function reduced_material_routine (material_model:: AbstractMaterialModel , F:: Tensor{2} , coefficient_cache, :: EmptyInternalCache , geometry_cache:: Ferrite.CellCache , qp:: QuadraturePoint , time)
26+ coefficients = evaluate_coefficient (coefficient_cache, geometry_cache, qp, time)
27+ return stress_function (material_model, F, coefficients, EmptyInternalModel ())
28+ end
29+
30+ function reduced_material_routine (material_model:: AbstractMaterialModel , F:: Tensor{2} , coefficient_cache, state_cache:: TrivialCondensationMaterialStateCache , geometry_cache:: Ferrite.CellCache , qp:: QuadraturePoint , time)
31+ coefficients = evaluate_coefficient (coefficient_cache, geometry_cache, qp, time)
32+ Q = state (state_cache, geometry_cache, qp, time)
33+ return stress_function (material_model, F, coefficients, Q)
34+ end
35+
36+ function reduced_material_routine (material_model:: AbstractMaterialModel , F:: Tensor{2} , coefficient_cache, state_cache:: RateIndependentCondensationMaterialStateCache , geometry_cache:: Ferrite.CellCache , qp:: QuadraturePoint , time)
37+ coefficients = evaluate_coefficient (coefficient_cache, geometry_cache, qp, time)
38+ Q = solve_local_constraint_state_only (F, coefficients, material_model, state_cache, geometry_cache, qp, time)
39+ P = stress_function (material_model, F, coefficients, Q)
40+ return P, ∂P∂F + ∂P∂QdQdF
41+ end
42+
2543@doc raw """
2644 PrestressedMechanicalModel(inner_model, prestress_field)
2745
@@ -92,11 +110,20 @@ default_initial_state!(uq, model::PK1Model) = default_initial_state!(uq, model.i
92110
93111setup_internal_cache (material_model:: PK1Model , qr:: QuadratureRule , sdh:: SubDofHandler ) = setup_internal_cache (material_model. internal_model, qr, sdh)
94112
113+ function stress_function (model:: PK1Model , F:: Tensor{2} , coefficients, :: EmptyInternalModel )
114+ ∂Ψ∂F = Tensors. gradient (
115+ F_ad -> Ψ (F_ad, coefficients, model. material),
116+ F
117+ )
118+
119+ return ∂Ψ∂F
120+ end
121+
95122function stress_and_tangent (model:: PK1Model , F:: Tensor{2} , coefficients, :: EmptyInternalModel )
96123 ∂²Ψ∂F², ∂Ψ∂F = Tensors. hessian (
97- F_ad ->
98- Ψ (F_ad, coefficients, model . material),
99- F, :all )
124+ F_ad -> Ψ (F_ad, coefficients, model . material),
125+ F, :all
126+ )
100127
101128 return ∂Ψ∂F, ∂²Ψ∂F²
102129end
@@ -163,6 +190,20 @@ function setup_coefficient_cache(m::ExtendedHillModel, qr::QuadratureRule, sdh::
163190 return setup_coefficient_cache (m. microstructure_model, qr, sdh)
164191end
165192
193+ function stress_function (model:: ExtendedHillModel , F:: Tensor{2} , coefficients, cell_state)
194+ # TODO what is a good abstraction here?
195+ Fᵃ = compute_Fᵃ (cell_state, coefficients, model. contraction_model, model. active_deformation_gradient_model)
196+ N = 𝓝 (cell_state, F, coefficients, model. contraction_model)
197+
198+ ∂Ψ∂F = Tensors. gradient (
199+ F_ad ->
200+ Ψ (F_ad, coefficients, model. passive_spring)
201+ + N* Ψ (F_ad, Fᵃ, coefficients, model. active_spring),
202+ F, :all )
203+
204+ return ∂Ψ∂F
205+ end
206+
166207function stress_and_tangent (model:: ExtendedHillModel , F:: Tensor{2} , coefficients, cell_state)
167208 # TODO what is a good abstraction here?
168209 Fᵃ = compute_Fᵃ (cell_state, coefficients, model. contraction_model, model. active_deformation_gradient_model)
@@ -202,6 +243,17 @@ function setup_coefficient_cache(m::ActiveStressModel, qr::QuadratureRule, sdh::
202243 return setup_coefficient_cache (m. microstructure_model, qr, sdh)
203244end
204245
246+ function stress_function (model:: ActiveStressModel , F:: Tensor{2} , coefficients, cell_state)
247+ ∂²Ψ∂F², ∂Ψ∂F = Tensors. gradient (
248+ F_ad -> Ψ (F_ad, coefficients, model. material_model),
249+ F
250+ )
251+
252+ P2 = 𝓝 (cell_state, F_ad, coefficients, model. contraction_model) * active_stress (model. active_stress_model, F_ad, coefficients)
253+ return ∂Ψ∂F + P2
254+ end
255+
256+
205257function stress_and_tangent (model:: ActiveStressModel , F:: Tensor{2} , coefficients, cell_state)
206258 ∂²Ψ∂F², ∂Ψ∂F = Tensors. hessian (
207259 F_ad ->
@@ -250,6 +302,49 @@ function _solve_local_sarcomere_dQdF(dQdλ, dλdF, λ, F, coefficients, active_t
250302 return - dQdF
251303end
252304
305+ # Local solve
306+ function solve_internal_timestep (material:: ActiveStressModel , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , λ, dλdt, Q, Qprev, Ca)
307+ @unpack Δt = state_cache
308+ # dsdt = sarcomere_rhs(s,λ,t)
309+ # <=> (sₜ₁ - sₜ₀) / Δt = sarcomere_rhs(sₜ₁,λₜ₁,t1)
310+
311+ function local_residual! (R, Q, λ, dλdt)
312+ dQ = zeros (eltype (Q), length (Q)) # TODO preallocate during setup
313+ sarcomere_rhs! (dQ, Q, λ, dλdt, Ca, time, material_model. contraction_model)
314+ @. . R = (Q - Qprev) / state_cache. Δt - dQ
315+ return nothing
316+ end
317+
318+ function local_residual_jac_wrap! (R, Q)
319+ return local_residual! (R, Q, λ, dλdt)
320+ end
321+
322+ R = state_cache. local_solver_cache. residual
323+ J = state_cache. local_solver_cache. J
324+ rtol = min (state_cache. local_solver_cache. params. tol, state_cache. local_solver_cache. outer_tol)
325+ for newton_iter in 1 : state_cache. local_solver_cache. params. max_iters
326+ ForwardDiff. jacobian! (J, local_residual_jac_wrap!, R, Q)
327+ local_residual! (R, Q, λ, dλdt)
328+ ΔQ = J \ R
329+ Q .- = ΔQ
330+ residualnorm = norm (R)
331+ if residualnorm < state_cache. local_solver_cache. params. tol
332+ break
333+ elseif newton_iter == state_cache. local_solver_cache. params. max_iters
334+ state_cache. local_solver_cache. retcode = SciMLBase. ReturnCode. MaxIters
335+ @debug " Reached maximum local Newton iterations at cell $(cellid (geometry_cache)) qp $(qp. i) . Aborting. ||r|| = $(residualnorm) " _group= :nlsolve
336+ return Q, J
337+ elseif isnan (residualnorm)
338+ state_cache. local_solver_cache. retcode = SciMLBase. ReturnCode. ConvergenceFailure
339+ @debug " Newton-Raphson diverged. Aborting. ||r|| = $residualnorm " _group= :nlsolve
340+ return Q, J
341+ end
342+ end
343+ ForwardDiff. jacobian! (J, local_residual_jac_wrap!, R, Q)
344+ state_cache. local_solver_cache. retcode = SciMLBase. ReturnCode. Success
345+ return Q, J
346+ end
347+
253348function solve_local_constraint (F:: Tensor{2,dim} , coefficients, material_model:: ActiveStressModel , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , geometry_cache, qp, time) where dim
254349 Qflat, Qprevflat = _query_local_state (state_cache, geometry_cache, qp)
255350 # Early out if any of the previous local solves failed
@@ -267,50 +362,7 @@ function solve_local_constraint(F::Tensor{2,dim}, coefficients, material_model::
267362 dλdt = 0.0 # TODO query
268363 Ca = evaluate_coefficient (state_cache. model_cache. calcium_cache, geometry_cache, qp, time)
269364
270- # Local solve
271- function solve_internal_timestep (material:: ActiveStressModel , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , λ, dλdt, Q, Qprev)
272- @unpack Δt = state_cache
273- # dsdt = sarcomere_rhs(s,λ,t)
274- # <=> (sₜ₁ - sₜ₀) / Δt = sarcomere_rhs(sₜ₁,λₜ₁,t1)
275-
276- function local_residual! (R, Q, λ, dλdt)
277- dQ = zeros (eltype (Q), length (Q)) # TODO preallocate during setup
278- sarcomere_rhs! (dQ, Q, λ, dλdt, Ca, time, material_model. contraction_model)
279- @. . R = (Q - Qprev) / state_cache. Δt - dQ
280- return nothing
281- end
282-
283- function local_residual_jac_wrap! (R, Q)
284- return local_residual! (R, Q, λ, dλdt)
285- end
286-
287- R = state_cache. local_solver_cache. residual
288- J = state_cache. local_solver_cache. J
289- rtol = min (state_cache. local_solver_cache. params. tol, state_cache. local_solver_cache. outer_tol)
290- for newton_iter in 1 : state_cache. local_solver_cache. params. max_iters
291- ForwardDiff. jacobian! (J, local_residual_jac_wrap!, R, Q)
292- local_residual! (R, Q, λ, dλdt)
293- ΔQ = J \ R
294- Q .- = ΔQ
295- residualnorm = norm (R)
296- if residualnorm < state_cache. local_solver_cache. params. tol
297- break
298- elseif newton_iter == state_cache. local_solver_cache. params. max_iters
299- state_cache. local_solver_cache. retcode = SciMLBase. ReturnCode. MaxIters
300- @debug " Reached maximum local Newton iterations at cell $(cellid (geometry_cache)) qp $(qp. i) . Aborting. ||r|| = $(residualnorm) " _group= :nlsolve
301- return Q, J
302- elseif isnan (residualnorm)
303- state_cache. local_solver_cache. retcode = SciMLBase. ReturnCode. ConvergenceFailure
304- @debug " Newton-Raphson diverged. Aborting. ||r|| = $residualnorm " _group= :nlsolve
305- return Q, J
306- end
307- end
308- ForwardDiff. jacobian! (J, local_residual_jac_wrap!, R, Q)
309- state_cache. local_solver_cache. retcode = SciMLBase. ReturnCode. Success
310- return Q, J
311- end
312-
313- Q, J = solve_internal_timestep (material_model, state_cache, λ, dλdt, Qflat, Qprevflat)
365+ Q, J = solve_internal_timestep (material_model, state_cache, λ, dλdt, Qflat, Qprevflat, Ca)
314366 # Abort if local solve failed
315367 if state_cache. local_solver_cache. retcode ∉ (SciMLBase. ReturnCode. Default, SciMLBase. ReturnCode. Success)
316368 return Qflat, zero (Tensor{4 ,dim,Float64,4 ^ dim})
@@ -333,6 +385,34 @@ function solve_local_constraint(F::Tensor{2,dim}, coefficients, material_model::
333385 return Q, _solve_local_sarcomere_dQdF (dQdλ, dλdF, λ, F, coefficients, material_model. active_stress_model, material_model. contraction_model)
334386end
335387
388+ function solve_local_constraint_state_only (F:: Tensor{2,dim} , coefficients, material_model:: ActiveStressModel , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , geometry_cache, qp, time) where dim
389+ Qflat, Qprevflat = _query_local_state (state_cache, geometry_cache, qp)
390+ # Early out if any of the previous local solves failed
391+ if state_cache. local_solver_cache. retcode ∉ (SciMLBase. ReturnCode. Default, SciMLBase. ReturnCode. Success)
392+ return Qflat, zero (Tensor{4 ,dim,Float64,4 ^ dim})
393+ end
394+
395+ function computeλ (F)
396+ f = F ⋅ coefficients. f
397+ return √ (f ⋅ f)
398+ end
399+
400+ # Frozen variables
401+ dλdF, λ = Tensors. gradient (computeλ, F, :all )
402+ dλdt = 0.0 # TODO query
403+ Ca = evaluate_coefficient (state_cache. model_cache. calcium_cache, geometry_cache, qp, time)
404+
405+ Q, J = solve_internal_timestep (material_model, state_cache, λ, dλdt, Qflat, Qprevflat, Ca)
406+ # Abort if local solve failed
407+ if state_cache. local_solver_cache. retcode ∉ (SciMLBase. ReturnCode. Default, SciMLBase. ReturnCode. Success)
408+ return Qflat, zero (Tensor{4 ,dim,Float64,4 ^ dim})
409+ end
410+ Qflat .= Q
411+ _store_local_state! (state_cache, geometry_cache, qp)
412+
413+ return Q
414+ end
415+
336416# Some debug materials
337417Base. @kwdef struct LinearMaxwellMaterial{T, sdim} <: AbstractMaterialModel
338418 E₀:: T
@@ -386,38 +466,36 @@ function _store_local_state!(state_cache::GenericFirstOrderRateIndependentConden
386466 return nothing
387467end
388468
389- function solve_local_constraint (F:: Tensor{2,dim} , coefficients, material_model:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , geometry_cache, qp, time) where dim
390- # Concept only for now.
391- function solve_internal_timestep (material:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , ε, εᵛflat, εᵛprevflat)
392- @unpack Δt = state_cache
393- εᵛ₁ = SymmetricTensor {2,dim} (εᵛflat)
394- εᵛ₀ = SymmetricTensor {2,dim} (εᵛprevflat)
395- # dεᵛdt = E₁/η₁ c : (ε - εᵛ)
396- # <=> (εᵛ₁ - εᵛ₀) / Δt = E₁/η₁ c : (ε - εᵛ₁) = E₁/η₁ c : ε - E₁/η₁ c : εᵛ₁
397- # <=> εᵛ₁ / Δt + E₁/η₁ c : εᵛ₁ = εᵛ₀/Δt + E₁/η₁ c : ε
398- # <=> (𝐈 / Δt + E₁/η₁ c) : εᵛ₁ = εᵛ₀/Δt + E₁/η₁ c : ε
469+ function solve_internal_timestep (material:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , ε, εᵛflat, εᵛprevflat)
470+ @unpack Δt = state_cache
471+ εᵛ₁ = SymmetricTensor {2,dim} (εᵛflat)
472+ εᵛ₀ = SymmetricTensor {2,dim} (εᵛprevflat)
473+ # dεᵛdt = E₁/η₁ c : (ε - εᵛ)
474+ # <=> (εᵛ₁ - εᵛ₀) / Δt = E₁/η₁ c : (ε - εᵛ₁) = E₁/η₁ c : ε - E₁/η₁ c : εᵛ₁
475+ # <=> εᵛ₁ / Δt + E₁/η₁ c : εᵛ₁ = εᵛ₀/Δt + E₁/η₁ c : ε
476+ # <=> (𝐈 / Δt + E₁/η₁ c) : εᵛ₁ = εᵛ₀/Δt + E₁/η₁ c : ε
399477
400- (; E₀, E₁, μ, η₁, ν) = material
401- I = one (ε)
402- c₁ = ν / ((ν + 1 )* (1 - 2 ν)) * I ⊗ I
403- c₂ = 1 / (1 + ν) * one (c₁)
404- ℂ = c₁ + c₂
478+ (; E₀, E₁, μ, η₁, ν) = material
479+ I = one (ε)
480+ c₁ = ν / ((ν + 1 )* (1 - 2 ν)) * I ⊗ I
481+ c₂ = 1 / (1 + ν) * one (c₁)
482+ ℂ = c₁ + c₂
405483
406- # FIXME non-allocating version by using state_cache nlsolver
407- A = tomandel (SMatrix, one (ℂ)/ Δt + E₁/ η₁ * ℂ)
408- b = tomandel (SVector, εᵛ₀/ Δt + E₁/ η₁ * ℂ ⊡ ε)
409- return frommandel (typeof (ε), A \ b)
410- end
484+ # FIXME non-allocating version by using state_cache nlsolver
485+ A = tomandel (SMatrix, one (ℂ)/ Δt + E₁/ η₁ * ℂ)
486+ b = tomandel (SVector, εᵛ₀/ Δt + E₁/ η₁ * ℂ ⊡ ε)
487+ return frommandel (typeof (ε), A \ b)
488+ end
411489
490+ function solve_local_constraint (F:: Tensor{2,dim} , coefficients, material_model:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , geometry_cache, qp, time) where dim
412491 Qflat, Qprevflat = _query_local_state (state_cache, geometry_cache, qp)
413492 ε = symmetric (F - one (F))
414493 Q = solve_internal_timestep (material_model, state_cache, ε, Qflat, Qprevflat)
415494 Qflat .= Q. data
416495 _store_local_state! (state_cache, geometry_cache, qp)
417496
418497 # Corrector
419- # Concept only for now.
420- function solve_internal_timestep_corrector (material:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , ε, εᵛflat, εᵛprevflat)
498+ function solve_internal_timestep_corrector (material:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , ε, εᵛflat, εᵛprevflat, coefficients)
421499 @unpack Δt = state_cache
422500 εᵛ₁ = SymmetricTensor {2,dim} (εᵛflat)
423501 εᵛ₀ = SymmetricTensor {2,dim} (εᵛprevflat)
@@ -436,12 +514,22 @@ function solve_local_constraint(F::Tensor{2,dim}, coefficients, material_model::
436514 B = tomandel (SMatrix, E₁/ η₁ * ℂ)
437515 return frommandel (typeof (ℂ), A \ B)
438516 end
439- dQdF = solve_internal_timestep_corrector (material_model, state_cache, ε, Qflat, Qprevflat)
517+ dQdF = solve_internal_timestep_corrector (material_model, state_cache, ε, Qflat, Qprevflat, coefficients )
440518 ∂P∂Q = Tensors. gradient (εᵛ-> stress_function (material_model, ε, coefficients, εᵛ), Q)
441519
442520 return Q, ∂P∂Q ⊡ dQdF
443521end
444522
523+ function solve_local_constraint_state_only (F:: Tensor{2,dim} , coefficients, material_model:: LinearMaxwellMaterial , state_cache:: GenericFirstOrderRateIndependentCondensationMaterialStateCache , geometry_cache, qp, time) where dim
524+ Qflat, Qprevflat = _query_local_state (state_cache, geometry_cache, qp)
525+ ε = symmetric (F - one (F))
526+ Q = solve_internal_timestep (material_model, state_cache, ε, Qflat, Qprevflat)
527+ Qflat .= Q. data
528+ _store_local_state! (state_cache, geometry_cache, qp)
529+
530+ return Q
531+ end
532+
445533function stress_function (material:: LinearMaxwellMaterial , ε, coefficients, εᵛ)
446534 (; E₀, E₁, μ, η₁, ν) = material
447535 I = one (ε)
0 commit comments