Skip to content

Conversation

@jmartfrut
Copy link
Collaborator

Introduces AnisoElastic and IsoElastic types and allows combination of isotropic and anisotropic models. It adds MultiElastic and MultiAnisoElastic to enable combination of multiple elastic models. It also enhances the TransverseIsotropy models to use the new AnisoElastic type.

Introduces `AnisoElastic` and `IsoElastic` types and allows
combination of isotropic and anisotropic models. It adds `MultiElastic`
and `MultiAnisoElastic` to enable combination of multiple elastic
models. It also enhances the TransverseIsotropy models to use the new
`AnisoElastic` type.
@jmartfrut jmartfrut requested a review from miguelmaso October 31, 2025 11:09
@github-actions
Copy link

github-actions bot commented Oct 31, 2025

Benchmark Results (Julia v1)

Time benchmarks
main 69d9c8f... main / 69d9c8f...
Constitutive models/Visco-elastic Ψ 0.0472 ± 0.027 ms 0.0474 ± 0.028 ms 0.996 ± 0.82
Constitutive models/Visco-elastic ∂Ψu 0.0614 ± 0.0033 ms 0.0614 ± 0.0031 ms 1 ± 0.074
Constitutive models/Visco-elastic ∂Ψuu 0.109 ± 0.015 ms 0.11 ± 0.015 ms 0.995 ± 0.19
Simulations/ViscoElastic 0.0468 h 0.0466 h 1
Tensor algebra/δδ_λ_2d 30 ± 0 ns 30 ± 0 ns 1 ± 0
Tensor algebra/δδ_μ_2d 30 ± 0 ns 30 ± 0 ns 1 ± 0
time_to_load 2.46 ± 0.021 s 2.48 ± 0.037 s 0.993 ± 0.017
Memory benchmarks
main 69d9c8f... main / 69d9c8f...
Constitutive models/Visco-elastic Ψ 1.24 k allocs: 0.0782 MB 1.24 k allocs: 0.0782 MB 1
Constitutive models/Visco-elastic ∂Ψu 1.36 k allocs: 0.0904 MB 1.36 k allocs: 0.0904 MB 1
Constitutive models/Visco-elastic ∂Ψuu 2.31 k allocs: 0.155 MB 2.31 k allocs: 0.155 MB 1
Simulations/ViscoElastic 2.72 G allocs: 192 GB 2.72 G allocs: 192 GB 1
Tensor algebra/δδ_λ_2d 0 allocs: 0 B 0 allocs: 0 B
Tensor algebra/δδ_μ_2d 0 allocs: 0 B 0 allocs: 0 B
time_to_load 0.149 k allocs: 11.1 kB 0.149 k allocs: 11.1 kB 1

Updates the test to use defined variables, resolving an error.
Copy link
Collaborator

@miguelmaso miguelmaso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks very good. The only concern from the point of view of design is that I'd keept the composed elastic as the sum of two isotropic models (current behaviour).

The main purpose of isotropic composition is to compose isochoric and volumteric parts like $\Psi_{iso} + \Psi_{vol}$, which is very common in literature.

On the other hand, viscous branches and isotropic directions are used to be expressed as vectors, $\Psi_\alpha$. This is why I like the MultiAnisoElastic.

In my opinion, when there is only one direction, iso + aniso1 internally should be interpreted as iso + [aniso] (like I posted in #40). On the contrary, if we allow ((iso1 + aniso1) + iso2 + aniso2) we would end with a recursive structure that will make very difficult to pass the tuple/list of direction.

To sumup, we must block the syntax iso + aniso1 + aniso2.

From the point of view of style, I'd moved anisotropic models to another file, but this is a minor question that can be left to another moment.

Comment on lines 106 to 124
function (obj::MultiElastic{<:AnisoElastic,<:AnisoElastic})(Λ::Float64=1.0)
DΨ1 = obj.Model1(Λ)
DΨ2 = obj.Model2(Λ)
Ψ, ∂Ψ, ∂∂Ψ = map((ψ1,ψ2) -> (x,N) -> ψ1(x,N) + ψ2(x,N), DΨ1, DΨ2)
return (Ψ, ∂Ψ, ∂∂Ψ)
end
function (obj::MultiElastic{<:IsoElastic,<:AnisoElastic})(Λ::Float64=1.0)
DΨ1 = obj.Model1(Λ)
DΨ2 = obj.Model2(Λ)
Ψ, ∂Ψ, ∂∂Ψ = map((ψ1,ψ2) -> (x,N) -> ψ1(x) + ψ2(x,N), DΨ1, DΨ2)
return (Ψ, ∂Ψ, ∂∂Ψ)
end
function (obj::ComposedElasticModel)(Λ::Float64=1.0)
function (obj::MultiElastic{<:AnisoElastic,<:IsoElastic})(Λ::Float64=1.0)
DΨ1 = obj.Model1(Λ)
DΨ2 = obj.Model2(Λ)
Ψ, ∂Ψ, ∂∂Ψ = map((ψ1,ψ2) -> (x,N) -> ψ1(x,N) + ψ2(x), DΨ1, DΨ2)
return (Ψ, ∂Ψ, ∂∂Ψ)
end
function (obj::MultiElastic{<:IsoElastic,<:IsoElastic})(Λ::Float64=1.0)
Copy link
Collaborator

@miguelmaso miguelmaso Oct 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very afraid of this: there are two possible ways to do the same thing. Typically, it'll end with bringing headaches

Changes the direct comparison in the tests to use `isapprox` with a relative tolerance.

This increases the stability and reliability of the tests by accounting for potential floating-point precision issues.
struct ComposedElasticModel <: Elasto
Model1::Elasto
Model2::Elasto
struct MultiElastic{A,B} <: Elasto
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the conversations, I propose to name it as ComposedIsoElastic

There is an idiomatic reason:

  • Composed -> +
  • Multi -> Tuple

function (obj::MultiElastic{<:AnisoElastic,<:AnisoElastic})(Λ::Float64=1.0)
DΨ1 = obj.Model1(Λ)
DΨ2 = obj.Model2(Λ)
Ψ, ∂Ψ, ∂∂Ψ = map((ψ1,ψ2) -> (x,N) -> ψ1(x,N) + ψ2(x,N), DΨ1, DΨ2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid map when there are only two variables. The code will be easer to read.

Implements composition of iso and aniso elastic models.
Allows combining models for more complex material behaviors.

Introduces `ComposedIsoElastic` and `ComposedAnisoElastic`
to handle the combinations. Composition of AnisoElastic models
is not allowed to avoid recurrence.
@jmartfrut
Copy link
Collaborator Author

@miguelmaso The following API supports the combination of:
iso + iso
iso + aniso
aniso + iso
iso + [aniso₁, aniso₂, ...]
Combinations of the form aniso + aniso are not supported, which also prevents the recurrence issue.

struct ComposedIsoElastic <: IsoElastic
  Model1::IsoElastic
  Model2::IsoElastic
  Kinematic
  function ComposedIsoElastic(model1::IsoElastic,model2::IsoElastic)
    new(model1,model2,model1.Kinematic)
  end
  function (obj::ComposedIsoElastic)(Λ::Float64=1.0)
    Ψ1, ∂Ψu1, ∂Ψuu1  = obj.Model1(Λ)
    Ψ2, ∂Ψu2, ∂Ψuu2  = obj.Model2(Λ)
    Ψ(x)=Ψ1(x)+Ψ2(x)
    ∂Ψ(x)=∂Ψu1(x)+∂Ψu2(x)
    ∂∂Ψ(x)=∂Ψuu1(x)+∂Ψuu2(x)
    return (Ψ, ∂Ψ, ∂∂Ψ)
  end
end
 
 
function (+)(Model1::IsoElastic, Model2::IsoElastic)
  ComposedIsoElastic(Model1,Model2)
end

struct ComposedAnisoElastic <: AnisoElastic
  Model1::IsoElastic
  Model2::AnisoElastic
  Kinematic
  function ComposedAnisoElastic(model1::IsoElastic,model2::AnisoElastic)
    new(model1,model2,model1.Kinematic)
  end
  function (obj::ComposedAnisoElastic)(Λ::Float64=1.0)
    DΨ1 = obj.Model1(Λ)
    DΨ2 = obj.Model2(Λ)
    Ψ, ∂Ψ, ∂∂Ψ = map((ψ1,ψ2) -> (x,N) -> ψ1(x) + ψ2(x,N), DΨ1, DΨ2)
    return (Ψ, ∂Ψ, ∂∂Ψ)
  end
end 
 

function (+)(Model1::IsoElastic, Model2::AnisoElastic)
  ComposedAnisoElastic(Model1,Model2)
end
function (+)(Model1::AnisoElastic, Model2::IsoElastic)
  ComposedAnisoElastic(Model2,Model1)
end

Allows combining IsoElastic and AnisoElastic constitutive models, creating a composed anisotropic elastic model.
This provides a more flexible way to define material behavior.

Removes commented-out code and unused variables.
Copy link
Collaborator

@miguelmaso miguelmaso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@jmartfrut jmartfrut merged commit 726ea64 into main Oct 31, 2025
4 checks passed
@jmartfrut jmartfrut deleted the ElastoAniso branch October 31, 2025 13:07
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.

3 participants