diff --git a/src/vector_conversion.jl b/src/vector_conversion.jl index 7e81b3e..8d6cf7f 100644 --- a/src/vector_conversion.jl +++ b/src/vector_conversion.jl @@ -66,26 +66,59 @@ get_params_eltype(::AbstractMaterial) = Float64 # Conversion functions """ - tovector!(v::AbstractVector, m::AbstractMaterial) + tovector!(v::AbstractVector, m::AbstractMaterial; offset = 0) + Put the material parameters of `m` into the vector `v`. This is typically used when the parameters should be fitted. - tovector!(v::AbstractVector, s::AbstractMaterialState) + tovector!(v::AbstractVector, s::AbstractMaterialState; offset = 0) + Put the state variables in `s` into the vector `v`. This is typically used when differentiating the material wrt. the the old state variables. + + tovector!(v::AbstractVector, a::Union{SecondOrderTensor, FourthOrderTensor}; offset = 0) + +Puts the Mandel components of `a` into the vector `v`. """ function tovector! end +# Tensors.jl implementation +function tovector!(v::AbstractVector, a::SecondOrderTensor; offset = 0) + return tomandel!(v, a; offset) +end +function tovector!(v::AbstractVector, a::Union{Tensor{4, <:Any, <:Any, M}, SymmetricTensor{4, <:Any, <:Any, M}}; offset = 0) where {M} + N = round(Int, sqrt(M)) + m = reshape(view(v, offset .+ (1:M)), (N, N)) + tomandel!(m, a) + return v +end + """ - fromvector(v::AbstractVector, ::MT) where {MT<:AbstractMaterial} + fromvector(v::AbstractVector, ::MT; offset = 0) where {MT<:AbstractMaterial} Create a material of type `MT` with the parameters according to `v` - fromvector(v::AbstractVector, ::ST) where {ST<:AbstractMaterialState} + fromvector(v::AbstractVector, ::ST; offset = 0) where {ST<:AbstractMaterialState} Create a material state of type `ST` with the values according to `v` + + fromvector(v, ::TT; offset = 0) where {TT <: Union{SecondOrderTensor, FourthOrderTensor}} + +Create a tensor with shape of `TT` with entries from the Mandel components in `v`. """ function fromvector end +# Tensors.jl implementation +function fromvector(v::AbstractVector, ::TT; offset = 0) where {TT <: SecondOrderTensor} + return frommandel(Tensors.get_base(TT), v; offset) +end + +function fromvector(v::AbstractVector, ::TT; offset = 0) where {TT <: FourthOrderTensor} + TB = Tensors.get_base(TT) + M = Tensors.n_components(TB) + N = round(Int, sqrt(M)) + return frommandel(TB, reshape(view(v, offset .+ (1:M)), (N, N))) +end + """ tovector(m::AbstractMaterial) @@ -108,6 +141,8 @@ function tovector(s::AbstractMaterialState) return tovector!(zeros(T, get_num_statevars(s)), s) end +tovector(a::Union{SecondOrderTensor, FourthOrderTensor}) = (m = tomandel(a); reshape(m, length(m))) + # Backwards compatibility const get_parameter_type = get_params_eltype const material2vector! = tovector! diff --git a/test/TestMaterials.jl b/test/TestMaterials.jl index 0eaa85c..e90147e 100644 --- a/test/TestMaterials.jl +++ b/test/TestMaterials.jl @@ -31,12 +31,12 @@ function MMB.material_response( end MMB.get_num_params(::LinearElastic) = 2 -function MMB.tovector!(v::Vector, m::LinearElastic) - v[1] = m.G - v[2] = m.K +function MMB.tovector!(v::Vector, m::LinearElastic; offset = 0) + v[1 + offset] = m.G + v[2 + offset] = m.K return v end -MMB.fromvector(v::Vector, ::LinearElastic) = LinearElastic(v[1], v[2]) +MMB.fromvector(v::Vector, ::LinearElastic; offset = 0) = LinearElastic(v[1 + offset], v[2 + offset]) function MMB.differentiate_material!( diff::MaterialDerivatives, diff --git a/test/runtests.jl b/test/runtests.jl index bb4e742..ca289c3 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,6 +8,7 @@ include("TestMaterials.jl") using .TestMaterials include("utils4testing.jl") +include("vector_conversion.jl") include("stressiterations.jl") include("differentiation.jl") include("errors.jl") diff --git a/test/vector_conversion.jl b/test/vector_conversion.jl new file mode 100644 index 0000000..51f5ee6 --- /dev/null +++ b/test/vector_conversion.jl @@ -0,0 +1,37 @@ +function test_invertible_conversion(x) + v1 = tovector(x) + # Basic test + @test isa(v1, AbstractVector) + @test v1 ≈ tovector(fromvector(v1, x)) + + # Ensure that we are not using the values in 'x' + v2 = rand(length(v1)) + @test v2 ≈ tovector(fromvector(v2, x)) + + # Ensure that offset is working as intended + v3 = zeros(length(v1) + 2) + r1, r2 = rand(2) + v3[1] = r1 + v3[end] = r2 + v4 = copy(v3) # Do copy here to keep 2:end-1 filled with zeros + tovector!(v3, x; offset = 1) + @test v3[1] == r1 + @test v3[end] == r2 + @test v3[2:end-1] ≈ v1 + @test v4 === tovector!(v4, fromvector(v3, x; offset = 1); offset = 1) + @test v3 ≈ v4 +end + +@testset "vector_conversion" begin + @testset "tensors" begin + @testset for TT in (Tensor{2,2}, Tensor{4,3}, SymmetricTensor{2,3}, SymmetricTensor{4,2}) + test_invertible_conversion(rand(TT)) + end + end + @testset "materials" begin + @testset for m in (LinearElastic(rand(), rand()),) + test_invertible_conversion(m) + # TODO: For state variables as well + end + end +end