Skip to content

Add FieldMatrix: a rank-two tensor generalisation of FieldVector #626

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 12, 2019
85 changes: 85 additions & 0 deletions src/FieldArray.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
"""
abstract FieldArray{N, T, D} <: StaticArray{N, T, D}

Inheriting from this type will make it easy to create your own rank-D tensor types. A `FieldArray`
will automatically define `getindex` and `setindex!` appropriately. An immutable
`FieldArray` will be as performant as an `SArray` of similar length and element type,
while a mutable `FieldArray` will behave similarly to an `MArray`.

For example:

struct Stiffness <: FieldArray{Tuple{2,2,2,2}, Float64, 4}
xxxx::Float64
xxxy::Float64
xxyx::Float64
xxyy::Float64
xyxx::Float64
xyxy::Float64
xyyx::Float64
xyyy::Float64
yxxx::Float64
yxxy::Float64
yxyx::Float64
yxyy::Float64
yyxx::Float64
yyxy::Float64
yyyx::Float64
yyyy::Float64
end
"""
abstract type FieldArray{N, T, D} <: StaticArray{N, T, D} end

"""
abstract FieldMatrix{N1, N2, T} <: FieldArray{Tuple{N1, N2}, 2}

Inheriting from this type will make it easy to create your own rank-two tensor types. A `FieldMatrix`
will automatically define `getindex` and `setindex!` appropriately. An immutable
`FieldMatrix` will be as performant as an `SMatrix` of similar length and element type,
while a mutable `FieldMatrix` will behave similarly to an `MMatrix`.

For example:

struct Stress <: FieldMatrix{3, 3, Float64}
xx::Float64
xy::Float64
xz::Float64
yx::Float64
yy::Float64
yz::Float64
zx::Float64
zy::Float64
zz::Float64
end
"""
abstract type FieldMatrix{N1, N2, T} <: FieldArray{Tuple{N1, N2}, T, 2} end

"""
abstract FieldVector{N, T} <: FieldArray{Tuple{N}, 1}

Inheriting from this type will make it easy to create your own vector types. A `FieldVector`
will automatically define `getindex` and `setindex!` appropriately. An immutable
`FieldVector` will be as performant as an `SVector` of similar length and element type,
while a mutable `FieldVector` will behave similarly to an `MVector`.

For example:

struct Point3D <: FieldVector{3, Float64}
x::Float64
y::Float64
z::Float64
end
"""
abstract type FieldVector{N, T} <: FieldArray{Tuple{N}, T, 1} end

@inline (::Type{FA})(x::Tuple{Vararg{Any, N}}) where {N, FA <: FieldArray} = if length(FA) == length(x)
FA(x...)
else
throw(DimensionMismatch("No precise constructor for $FA found. Length of input was $(length(x))."))
end

@propagate_inbounds getindex(a::FieldArray, i::Int) = getfield(a, i)
@propagate_inbounds setindex!(a::FieldArray, x, i::Int) = setfield!(a, i, x)

Base.cconvert(::Type{<:Ptr}, a::FieldArray) = Base.RefValue(a)
Base.unsafe_convert(::Type{Ptr{T}}, m::Base.RefValue{FA}) where {N,T,D,FA<:FieldArray{N,T,D}} =
Ptr{T}(Base.unsafe_convert(Ptr{FA}, m))
28 changes: 0 additions & 28 deletions src/FieldVector.jl

This file was deleted.

6 changes: 3 additions & 3 deletions src/StaticArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export SOneTo
export StaticScalar, StaticArray, StaticVector, StaticMatrix
export Scalar, SArray, SVector, SMatrix
export MArray, MVector, MMatrix
export FieldVector
export FieldVector, FieldMatrix, FieldArray
export SizedArray, SizedVector, SizedMatrix
export SDiagonal
export SHermitianCompact
Expand Down Expand Up @@ -71,7 +71,7 @@ For mutable containers you may also need to define the following:
- In some cases, a zero-parameter constructor, `MyStaticArray{...}()` for unintialized data
is assumed to exist.

(see also `SVector`, `SMatrix`, `SArray`, `MVector`, `MMatrix`, `MArray`, `SizedArray` and `FieldVector`)
(see also `SVector`, `SMatrix`, `SArray`, `MVector`, `MMatrix`, `MArray`, `SizedArray`, `FieldVector`, `FieldMatrix` and `FieldArray`)
"""
abstract type StaticArray{S <: Tuple, T, N} <: AbstractArray{T, N} end
const StaticScalar{T} = StaticArray{Tuple{}, T, 0}
Expand Down Expand Up @@ -101,7 +101,7 @@ include("util.jl")
include("traits.jl")

include("SUnitRange.jl")
include("FieldVector.jl")
include("FieldArray.jl")
include("SArray.jl")
include("SMatrix.jl")
include("SVector.jl")
Expand Down
104 changes: 104 additions & 0 deletions test/FieldMatrix.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
@testset "FieldMatrix" begin
@testset "Immutable Tensor3x3" begin
eval(quote
struct Tensor3x3 <: FieldMatrix{3, 3, Float64}
xx::Float64
xy::Float64
xz::Float64
yx::Float64
yy::Float64
yz::Float64
zx::Float64
zy::Float64
zz::Float64
end

StaticArrays.similar_type(::Type{Tensor3x3}, ::Type{Float64}, s::Size{(3,3)}) = Tensor3x3
end)

p = Tensor3x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)

@test_throws Exception p[2] = 4.0
@test_throws Exception p[2, 3] = 6.0

@test size(p) === (3,3)
@test length(p) === 9
@test eltype(p) === Float64

@testinf Tuple(p) === (1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)

@test (p + p) === Tensor3x3(2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)

@test (p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]) === (p.xx, p.xy, p.xz, p.yx, p.yy, p.yz, p.zx, p.zy, p.zz)

m = @SMatrix [2.0 0.0 0.0;
0.0 2.0 0.0;
0.0 0.0 2.0]

@test @inferred(p*m) === Tensor3x3(2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)

@test @inferred(similar_type(Tensor3x3)) == Tensor3x3
@test @inferred(similar_type(Tensor3x3, Float64)) == Tensor3x3
@test @inferred(similar_type(Tensor3x3, Float32)) == SMatrix{3,3,Float32,9}
@test @inferred(similar_type(Tensor3x3, Size(4,4))) == SMatrix{4,4,Float64,16}
@test @inferred(similar_type(Tensor3x3, Float32, Size(4,4))) == SMatrix{4,4,Float32,16}

# Issue 146
@test [[Tensor3x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)]; [Tensor3x3(2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)]]::Vector{Tensor3x3} == [Tensor3x3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0), Tensor3x3(2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 18.0)]

# Issue 342
@test_throws DimensionMismatch("No precise constructor for Tensor3x3 found. Length of input was 10.") Tensor3x3(1,2,3,4,5,6,7,8,9,10)
end

@testset "Mutable Tensor2x2" begin
eval(quote
mutable struct Tensor2x2{T} <: FieldMatrix{2, 2, T}
xx::T
xy::T
yx::T
yy::T
end

StaticArrays.similar_type(::Type{P2D}, ::Type{T}, s::Size{(2,2)}) where {P2D<:Tensor2x2,T} = Tensor2x2{T}
end)

p = Tensor2x2(0.0, 0.0, 0.0, 0.0)
p[1,1] = 1.0
p[2,1] = 2.0

@test size(p) === (2,2)
@test length(p) === 4
@test eltype(p) === Float64

@testinf Tuple(p) === (1.0, 2.0, 0.0, 0.0)

@test (p[1], p[2], p[3], p[4]) === (p.xx, p.xy, p.yx, p.yy)
@test (p[1], p[2], p[3], p[4]) === (1.0, 2.0, 0.0, 0.0)

m = @SMatrix [2.0 0.0;
0.0 2.0]

@test @inferred(p*m)::Tensor2x2 == Tensor2x2(2.0, 4.0, 0.0, 0.0)

@test @inferred(similar_type(Tensor2x2{Float64})) == Tensor2x2{Float64}
@test @inferred(similar_type(Tensor2x2{Float64}, Float32)) == Tensor2x2{Float32}
@test @inferred(similar_type(Tensor2x2{Float64}, Size(3,3))) == SMatrix{3,3,Float64,9}
@test @inferred(similar_type(Tensor2x2{Float64}, Float32, Size(4,4))) == SMatrix{4,4,Float32,16}
end

@testset "FieldMatrix with Tuple fields" begin
# verify that having a field which is itself a Tuple
# doesn't break anything

eval(quote
struct TupleField2 <: FieldMatrix{1, 1, NTuple{2, Int}}
x::NTuple{2, Int}
end
end)

x = TupleField2((1,2))
@test length(x) == 1
@test length(x[1]) == 2
@test x.x == (1, 2)
end
end
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ include("MMatrix.jl")
include("SArray.jl")
include("MArray.jl")
include("FieldVector.jl")
include("FieldMatrix.jl")
include("Scalar.jl")
include("SUnitRange.jl")
include("SizedArray.jl")
Expand Down