changeset 1143:9275d95e2d90 refactor/grids

Merge with default
author Jonatan Werpers <jonatan@werpers.com>
date Wed, 19 Oct 2022 22:36:02 +0200
parents c4ea28d904f5 (current diff) 0aa8ce9f30e2 (diff)
children cfe6a09974fb
files src/Grids/EquidistantGrid.jl src/Grids/equidistant_grid.jl test/Grids/EquidistantGrid_test.jl test/Grids/equidistant_grid_test.jl
diffstat 19 files changed, 539 insertions(+), 419 deletions(-) [+]
line wrap: on
line diff
--- a/Manifest.toml	Wed Apr 27 10:25:53 2022 +0200
+++ b/Manifest.toml	Wed Oct 19 22:36:02 2022 +0200
@@ -1,25 +1,50 @@
 # This file is machine-generated - editing it directly is not advised
 
-julia_version = "1.7.1"
+julia_version = "1.8.2"
 manifest_format = "2.0"
+project_hash = "b024d6898b484706c36ee3b2a041918f3a9d2088"
 
 [[deps.Adapt]]
 deps = ["LinearAlgebra"]
-git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f"
+git-tree-sha1 = "195c5505521008abea5aee4f96930717958eac6f"
 uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
-version = "3.3.3"
+version = "3.4.0"
+
+[[deps.ArrayInterface]]
+deps = ["ArrayInterfaceCore", "Compat", "IfElse", "LinearAlgebra", "Static"]
+git-tree-sha1 = "d6173480145eb632d6571c148d94b9d3d773820e"
+uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
+version = "6.0.23"
+
+[[deps.ArrayInterfaceCore]]
+deps = ["LinearAlgebra", "SparseArrays", "SuiteSparse"]
+git-tree-sha1 = "5bb0f8292405a516880a3809954cb832ae7a31c5"
+uuid = "30b0a656-2188-435a-8636-2ec0e6a096e2"
+version = "0.1.20"
 
 [[deps.Artifacts]]
 uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
 
+[[deps.Compat]]
+deps = ["Dates", "LinearAlgebra", "UUIDs"]
+git-tree-sha1 = "5856d3031cdb1f3b2b6340dfdc66b6d9a149a374"
+uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
+version = "4.2.0"
+
 [[deps.CompilerSupportLibraries_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
+version = "0.5.2+0"
 
 [[deps.Dates]]
 deps = ["Printf"]
 uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
 
+[[deps.IfElse]]
+git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1"
+uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
+version = "0.1.1"
+
 [[deps.Libdl]]
 uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
 
@@ -29,27 +54,58 @@
 
 [[deps.OffsetArrays]]
 deps = ["Adapt"]
-git-tree-sha1 = "043017e0bdeff61cfbb7afeb558ab29536bbb5ed"
+git-tree-sha1 = "1ea784113a6aa054c5ebd95945fa5e52c2f378e7"
 uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
-version = "1.10.8"
+version = "1.12.7"
 
 [[deps.OpenBLAS_jll]]
 deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
 uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
+version = "0.3.20+0"
 
 [[deps.Printf]]
 deps = ["Unicode"]
 uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
 
+[[deps.Random]]
+deps = ["SHA", "Serialization"]
+uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
+
+[[deps.SHA]]
+uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
+version = "0.7.0"
+
+[[deps.Serialization]]
+uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
+
+[[deps.SparseArrays]]
+deps = ["LinearAlgebra", "Random"]
+uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
+
+[[deps.Static]]
+deps = ["IfElse"]
+git-tree-sha1 = "de4f0a4f049a4c87e4948c04acff37baf1be01a6"
+uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
+version = "0.7.7"
+
+[[deps.SuiteSparse]]
+deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
+uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"
+
 [[deps.TOML]]
 deps = ["Dates"]
 uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+version = "1.0.0"
 
 [[deps.TiledIteration]]
-deps = ["OffsetArrays"]
-git-tree-sha1 = "5683455224ba92ef59db72d10690690f4a8dc297"
+deps = ["ArrayInterface", "OffsetArrays"]
+git-tree-sha1 = "5e02b75701f1905e55e44fc788bd13caedb5a6e3"
 uuid = "06e1c1a7-607b-532d-9fad-de7d9aa2abac"
-version = "0.3.1"
+version = "0.4.1"
+
+[[deps.UUIDs]]
+deps = ["Random", "SHA"]
+uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
 
 [[deps.Unicode]]
 uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
@@ -57,3 +113,4 @@
 [[deps.libblastrampoline_jll]]
 deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
 uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
+version = "5.1.1+0"
--- a/src/Grids/AbstractGrid.jl	Wed Apr 27 10:25:53 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-"""
-     AbstractGrid
-
-Should implement
-    dimension(grid::AbstractGrid)
-    points(grid::AbstractGrid)
-
-"""
-abstract type AbstractGrid end
-export AbstractGrid
-function dimension end
-function points end
-export dimension, points
-
-"""
-    evalOn(g::AbstractGrid, f::Function)
-
-Evaluate function f on the grid g
-"""
-function evalOn(g::AbstractGrid, f::Function)
-    F(x) = f(x...)
-    return F.(points(g))
-end
-export evalOn
--- a/src/Grids/EquidistantGrid.jl	Wed Apr 27 10:25:53 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,192 +0,0 @@
-export EquidistantGrid
-export spacing
-export inverse_spacing
-export restrict
-export boundary_identifiers
-export boundary_grid
-export refine
-export coarsen
-
-"""
-    EquidistantGrid{Dim,T<:Real} <: AbstractGrid
-
-`Dim`-dimensional equidistant grid with coordinates of type `T`.
-"""
-struct EquidistantGrid{Dim,T<:Real} <: AbstractGrid
-    size::NTuple{Dim, Int}
-    limit_lower::NTuple{Dim, T}
-    limit_upper::NTuple{Dim, T}
-
-    function EquidistantGrid{Dim,T}(size::NTuple{Dim, Int}, limit_lower::NTuple{Dim, T}, limit_upper::NTuple{Dim, T}) where {Dim,T}
-        if any(size .<= 0)
-            throw(DomainError("all components of size must be postive"))
-        end
-        if any(limit_upper.-limit_lower .<= 0)
-            throw(DomainError("all side lengths must be postive"))
-        end
-        return new{Dim,T}(size, limit_lower, limit_upper)
-    end
-end
-
-"""
-    EquidistantGrid(size, limit_lower, limit_upper)
-
-Construct an equidistant grid with corners at the coordinates `limit_lower` and
-`limit_upper`.
-
-The length of the domain sides are given by the components of
-`limit_upper-limit_lower`. E.g for a 2D grid with `limit_lower=(-1,0)` and `limit_upper=(1,2)` the domain is defined
-as `(-1,1)x(0,2)`. The side lengths of the grid are not allowed to be negative.
-
-The number of equidistantly spaced points in each coordinate direction are given
-by the tuple `size`.
-"""
-function EquidistantGrid(size, limit_lower, limit_upper)
-    return EquidistantGrid{length(size), eltype(limit_lower)}(size, limit_lower, limit_upper)
-end
-# TBD: Should it be an AbstractArray?
-
-"""
-    EquidistantGrid{T}()
-
-Constructs a 0-dimensional grid.
-"""
-EquidistantGrid{T}() where T = EquidistantGrid{0,T}((),(),()) # Convenience constructor for 0-dim grid
-
-"""
-    EquidistantGrid(size::Int, limit_lower::T, limit_upper::T)
-
-Convenience constructor for 1D grids.
-"""
-function EquidistantGrid(size::Int, limit_lower::T, limit_upper::T) where T
-	return EquidistantGrid((size,),(limit_lower,),(limit_upper,))
-end
-
-Base.eltype(grid::EquidistantGrid{Dim,T}) where {Dim,T} = T
-
-Base.eachindex(grid::EquidistantGrid) = CartesianIndices(grid.size)
-
-Base.size(g::EquidistantGrid) = g.size
-
-function Base.getindex(g::EquidistantGrid, I::Vararg{Int})
-    h = spacing(g)
-    return g.limit_lower .+ (I.-1).*h
-end
-
-Base.getindex(g::EquidistantGrid, I::CartesianIndex) = g[Tuple(I)...]
-# TBD: Can this method be removed if `EquidistantGrid` is an AbstractArray?
-
-"""
-    dimension(grid::EquidistantGrid)
-
-The dimension of the grid.
-"""
-dimension(grid::EquidistantGrid{Dim}) where Dim = Dim
-
-"""
-    spacing(grid::EquidistantGrid)
-
-The spacing between grid points.
-"""
-spacing(grid::EquidistantGrid) = (grid.limit_upper.-grid.limit_lower)./(grid.size.-1)
-
-"""
-    inverse_spacing(grid::EquidistantGrid)
-
-The reciprocal of the spacing between grid points.
-"""
-inverse_spacing(grid::EquidistantGrid) = 1 ./ spacing(grid)
-
-"""
-    points(grid::EquidistantGrid)
-
-The point of the grid as an array of tuples with the same dimension as the grid.
-The points are stored as [(x1,y1), (x1,y2), … (x1,yn);
-						  (x2,y1), (x2,y2), … (x2,yn);
-						  	⋮		 ⋮            ⋮
-						  (xm,y1), (xm,y2), … (xm,yn)]
-"""
-function points(grid::EquidistantGrid)
-    indices = Tuple.(CartesianIndices(grid.size))
-    h = spacing(grid)
-    return broadcast(I -> grid.limit_lower .+ (I.-1).*h, indices)
-end
-
-"""
-    restrict(::EquidistantGrid, dim)
-
-Pick out given dimensions from the grid and return a grid for them.
-"""
-function restrict(grid::EquidistantGrid, dim)
-    size = grid.size[dim]
-    limit_lower = grid.limit_lower[dim]
-    limit_upper = grid.limit_upper[dim]
-
-    return EquidistantGrid(size, limit_lower, limit_upper)
-end
-
-"""
-    boundary_identifiers(::EquidistantGrid)
-
-Returns a tuple containing the boundary identifiers for the grid, stored as
-	(CartesianBoundary(1,Lower),
-	 CartesianBoundary(1,Upper),
-	 CartesianBoundary(2,Lower),
-	 ...)
-"""
-boundary_identifiers(g::EquidistantGrid) = (((ntuple(i->(CartesianBoundary{i,Lower}(),CartesianBoundary{i,Upper}()),dimension(g)))...)...,)
-
-
-"""
-    boundary_grid(grid::EquidistantGrid,id::CartesianBoundary)
-	boundary_grid(::EquidistantGrid{1},::CartesianBoundary{1})
-
-Creates the lower-dimensional restriciton of `grid` spanned by the dimensions
-orthogonal to the boundary specified by `id`. The boundary grid of a 1-dimensional
-grid is a zero-dimensional grid.
-"""
-function boundary_grid(grid::EquidistantGrid,id::CartesianBoundary)
-	dims = collect(1:dimension(grid))
-	orth_dims = dims[dims .!= dim(id)]
-	if orth_dims == dims
-		throw(DomainError("boundary identifier not matching grid"))
-	end
-    return restrict(grid,orth_dims)
-end
-boundary_grid(::EquidistantGrid{1,T},::CartesianBoundary{1}) where T = EquidistantGrid{T}()
-
-
-"""
-    refine(grid::EquidistantGrid, r::Int)
-
-Refines `grid` by a factor `r`. The factor is applied to the number of
-intervals which is 1 less than the size of the grid.
-
-See also: [`coarsen`](@ref)
-"""
-function refine(grid::EquidistantGrid, r::Int)
-    sz = size(grid)
-    new_sz = (sz .- 1).*r .+ 1
-    return EquidistantGrid{dimension(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper)
-end
-
-"""
-    coarsen(grid::EquidistantGrid, r::Int)
-
-Coarsens `grid` by a factor `r`. The factor is applied to the number of
-intervals which is 1 less than the size of the grid. If the number of
-intervals are not divisible by `r` an error is raised.
-
-See also: [`refine`](@ref)
-"""
-function coarsen(grid::EquidistantGrid, r::Int)
-    sz = size(grid)
-
-    if !all(n -> (n % r == 0), sz.-1)
-        throw(DomainError(r, "Size minus 1 must be divisible by the ratio."))
-    end
-
-    new_sz = (sz .- 1).÷r .+ 1
-
-    return EquidistantGrid{dimension(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper)
-end
--- a/src/Grids/Grids.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/Grids/Grids.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -2,18 +2,30 @@
 
 using Sbplib.RegionIndices
 
-export BoundaryIdentifier, CartesianBoundary
+# Grid
+export Grid
+export dims
+export points
+export evalOn
 
-abstract type BoundaryIdentifier end
-struct CartesianBoundary{Dim, R<:Region} <: BoundaryIdentifier end
-dim(::CartesianBoundary{Dim, R}) where {Dim, R} = Dim
-region(::CartesianBoundary{Dim, R}) where {Dim, R} = R()
+# BoundaryIdentifier
+export BoundaryIdentifier
+export CartesianBoundary
+export dim
+export region
 
-export dim, region
+# EquidistantGrid
+export EquidistantGrid
+export spacing
+export inverse_spacing
+export restrict
+export boundary_identifiers
+export boundary_grid
+export refine
+export coarsen
 
-include("AbstractGrid.jl")
-include("EquidistantGrid.jl")
-
-# TODO: Rename AbstractGrid to Grid and move definition here.
+include("grid.jl")
+include("boundary_identifier.jl")
+include("equidistant_grid.jl")
 
 end # module
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Grids/boundary_identifier.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -0,0 +1,6 @@
+
+abstract type BoundaryIdentifier end
+
+struct CartesianBoundary{Dim, R<:Region} <: BoundaryIdentifier end
+dim(::CartesianBoundary{Dim, R}) where {Dim, R} = Dim
+region(::CartesianBoundary{Dim, R}) where {Dim, R} = R()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Grids/equidistant_grid.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -0,0 +1,196 @@
+
+"""
+    EquidistantGrid{Dim,T<:Real} <: Grid
+
+`Dim`-dimensional equidistant grid with coordinates of type `T`.
+"""
+struct EquidistantGrid{Dim,T<:Real} <: Grid
+    size::NTuple{Dim, Int}
+    limit_lower::NTuple{Dim, T}
+    limit_upper::NTuple{Dim, T}
+
+    function EquidistantGrid{Dim,T}(size::NTuple{Dim, Int}, limit_lower::NTuple{Dim, T}, limit_upper::NTuple{Dim, T}) where {Dim,T}
+        if any(size .<= 0)
+            throw(DomainError("all components of size must be postive"))
+        end
+        if any(limit_upper.-limit_lower .<= 0)
+            throw(DomainError("all side lengths must be postive"))
+        end
+        return new{Dim,T}(size, limit_lower, limit_upper)
+    end
+end
+
+"""
+    EquidistantGrid(size, limit_lower, limit_upper)
+
+Construct an equidistant grid with corners at the coordinates `limit_lower` and
+`limit_upper`.
+
+The length of the domain sides are given by the components of
+`limit_upper-limit_lower`. E.g for a 2D grid with `limit_lower=(-1,0)` and `limit_upper=(1,2)` the domain is defined
+as `(-1,1)x(0,2)`. The side lengths of the grid are not allowed to be negative.
+
+The number of equidistantly spaced points in each coordinate direction are given
+by the tuple `size`.
+"""
+function EquidistantGrid(size, limit_lower, limit_upper)
+    return EquidistantGrid{length(size), eltype(limit_lower)}(size, limit_lower, limit_upper)
+end
+# TBD: Should it be an AbstractArray?
+
+"""
+    EquidistantGrid{T}()
+
+Constructs a 0-dimensional grid.
+"""
+EquidistantGrid{T}() where T = EquidistantGrid{0,T}((),(),()) # Convenience constructor for 0-dim grid
+
+
+"""
+    EquidistantGrid(size::Int, limit_lower::T, limit_upper::T)
+
+Convenience constructor for 1D grids.
+"""
+function EquidistantGrid(size::Int, limit_lower::T, limit_upper::T) where T
+	return EquidistantGrid((size,),(limit_lower,),(limit_upper,))
+end
+
+Base.eltype(grid::EquidistantGrid{Dim,T}) where {Dim,T} = T
+
+Base.eachindex(grid::EquidistantGrid) = CartesianIndices(grid.size)
+
+Base.size(g::EquidistantGrid) = g.size
+
+Base.ndims(::EquidistantGrid{Dim}) where Dim = Dim
+
+function Base.getindex(g::EquidistantGrid, I::Vararg{Int})
+    h = spacing(g)
+    return g.limit_lower .+ (I.-1).*h
+end
+
+Base.getindex(g::EquidistantGrid, I::CartesianIndex) = g[Tuple(I)...]
+# TBD: Can this method be removed if `EquidistantGrid` is an AbstractArray?
+
+
+
+
+"""
+    spacing(grid::EquidistantGrid)
+
+The spacing between grid points.
+"""
+spacing(grid::EquidistantGrid) = (grid.limit_upper.-grid.limit_lower)./(grid.size.-1)
+
+
+"""
+    inverse_spacing(grid::EquidistantGrid)
+
+The reciprocal of the spacing between grid points.
+"""
+inverse_spacing(grid::EquidistantGrid) = 1 ./ spacing(grid)
+
+
+"""
+    points(grid::EquidistantGrid)
+
+The point of the grid as an array of tuples with the same dimension as the grid.
+The points are stored as [(x1,y1), (x1,y2), … (x1,yn);
+						  (x2,y1), (x2,y2), … (x2,yn);
+						  	⋮		 ⋮            ⋮
+						  (xm,y1), (xm,y2), … (xm,yn)]
+"""
+function points(grid::EquidistantGrid)
+    indices = Tuple.(CartesianIndices(grid.size))
+    h = spacing(grid)
+    return broadcast(I -> grid.limit_lower .+ (I.-1).*h, indices)
+end
+
+"""
+    restrict(::EquidistantGrid, dim)
+
+Pick out given dimensions from the grid and return a grid for them.
+"""
+function restrict(grid::EquidistantGrid, dim)
+    size = grid.size[dim]
+    limit_lower = grid.limit_lower[dim]
+    limit_upper = grid.limit_upper[dim]
+
+    return EquidistantGrid(size, limit_lower, limit_upper)
+end
+
+
+"""
+    orthogonal_dims(grid::EquidistantGrid,dim)
+
+Returns the dimensions of grid orthogonal to that of dim.
+"""
+function orthogonal_dims(grid::EquidistantGrid, dim)
+    orth_dims = filter(i -> i != dim, dims(grid))
+	if orth_dims == dims(grid)
+		throw(DomainError(string("dimension ",string(dim)," not matching grid")))
+	end
+    return orth_dims
+end
+
+
+"""
+    boundary_identifiers(::EquidistantGrid)
+
+Returns a tuple containing the boundary identifiers for the grid, stored as
+	(CartesianBoundary(1,Lower),
+	 CartesianBoundary(1,Upper),
+	 CartesianBoundary(2,Lower),
+	 ...)
+"""
+boundary_identifiers(g::EquidistantGrid) = (((ntuple(i->(CartesianBoundary{i,Lower}(),CartesianBoundary{i,Upper}()),ndims(g)))...)...,)
+
+
+"""
+    boundary_grid(grid::EquidistantGrid, id::CartesianBoundary)
+
+Creates the lower-dimensional restriciton of `grid` spanned by the dimensions
+orthogonal to the boundary specified by `id`. The boundary grid of a 1-dimensional
+grid is a zero-dimensional grid.
+"""
+function boundary_grid(grid::EquidistantGrid, id::CartesianBoundary)
+    orth_dims = orthogonal_dims(grid, dim(id))
+    return restrict(grid, orth_dims)
+end
+boundary_grid(::EquidistantGrid{1,T},::CartesianBoundary{1}) where T = EquidistantGrid{T}()
+
+
+"""
+    refine(grid::EquidistantGrid, r::Int)
+
+Refines `grid` by a factor `r`. The factor is applied to the number of
+intervals which is 1 less than the size of the grid.
+
+See also: [`coarsen`](@ref)
+"""
+function refine(grid::EquidistantGrid, r::Int)
+    sz = size(grid)
+    new_sz = (sz .- 1).*r .+ 1
+    return EquidistantGrid{ndims(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper)
+end
+
+
+"""
+    coarsen(grid::EquidistantGrid, r::Int)
+
+Coarsens `grid` by a factor `r`. The factor is applied to the number of
+intervals which is 1 less than the size of the grid. If the number of
+intervals are not divisible by `r` an error is raised.
+
+See also: [`refine`](@ref)
+"""
+function coarsen(grid::EquidistantGrid, r::Int)
+    sz = size(grid)
+
+    if !all(n -> (n % r == 0), sz.-1)
+        throw(DomainError(r, "Size minus 1 must be divisible by the ratio."))
+    end
+
+    new_sz = (sz .- 1).÷r .+ 1
+
+    return EquidistantGrid{ndims(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Grids/grid.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -0,0 +1,27 @@
+"""
+     Grid
+
+Should implement
+    Base.ndims(grid::Grid)
+    points(grid::Grid)
+
+"""
+abstract type Grid end
+function points end
+
+"""
+    dims(grid::Grid)
+
+A range containing the dimensions of `grid`
+"""
+dims(grid::Grid) = 1:ndims(grid)
+
+"""
+    evalOn(grid::Grid, f::Function)
+
+Evaluate function `f` on `grid`
+"""
+function evalOn(grid::Grid, f::Function)
+    F(x) = f(x...)
+    return F.(points(grid))
+end
--- a/src/LazyTensors/lazy_array.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/LazyTensors/lazy_array.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -93,17 +93,22 @@
 
 
 
-# NOTE: Är det knas att vi har till exempel * istället för .* ??
-# Oklart om det ens går att lösa..
+# Overload +,-,*,/ for LazyArrays 
+# Element wise operation for `*` and `/` are not overloaded for due to conflicts with the behavior
+# of regular `*` and `/` for AbstractArrays. Use tilde versions instead.
 Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b
+Base.@propagate_inbounds Base.:-(a::LazyArray{T,D}, b::LazyArray{T,D}) where {T,D} = a -̃ b
+
 Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::AbstractArray{T,D}) where {T,D} = a +̃ b
-Base.@propagate_inbounds Base.:+(a::AbstractArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b
+Base.@propagate_inbounds Base.:-(a::LazyArray{T,D}, b::AbstractArray{T,D}) where {T,D} = a -̃ b
 
-Base.@propagate_inbounds Base.:-(a::LazyArray{T,D}, b::LazyArray{T,D}) where {T,D} = a -̃ b
-Base.@propagate_inbounds Base.:-(a::LazyArray{T,D}, b::AbstractArray{T,D}) where {T,D} = a -̃ b
+Base.@propagate_inbounds Base.:+(a::AbstractArray{T,D}, b::LazyArray{T,D}) where {T,D} = a +̃ b
 Base.@propagate_inbounds Base.:-(a::AbstractArray{T,D}, b::LazyArray{T,D}) where {T,D} = a -̃ b
 
-# Element wise operation for `*` and `\` are not overloaded due to conflicts with the behavior
-# of regular `*` and `/` for AbstractArrays. Use tilde versions instead.
+Base.@propagate_inbounds Base.:+(a::LazyArray{T,D}, b::T) where {T,D} = a +̃ b
+Base.@propagate_inbounds Base.:-(a::LazyArray{T,D}, b::T) where {T,D} = a -̃ b
+
+Base.@propagate_inbounds Base.:+(a::T, b::LazyArray{T,D}) where {T,D} = a +̃ b
+Base.@propagate_inbounds Base.:-(a::T, b::LazyArray{T,D}) where {T,D} = a -̃  b
 
 export +̃, -̃, *̃, /̃
--- a/src/LazyTensors/lazy_tensor_operations.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/LazyTensors/lazy_tensor_operations.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -98,7 +98,6 @@
     apply_transpose(c.t2, c.t1'*v, I...)
 end
 
-
 """
     TensorComposition(tm, tmi::IdentityTensor)
     TensorComposition(tmi::IdentityTensor, tm)
@@ -120,6 +119,8 @@
     return tmi
 end
 
+Base.:*(a::T, tm::LazyTensor{T}) where T = TensorComposition(ScalingTensor{T,range_dim(tm)}(a,range_size(tm)), tm)
+Base.:*(tm::LazyTensor{T}, a::T) where T = a*tm
 
 """
     InflatedTensor{T,R,D} <: LazyTensor{T,R,D}
--- a/src/SbpOperators/boundaryops/boundary_operator.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/SbpOperators/boundaryops/boundary_operator.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -18,7 +18,7 @@
     op = BoundaryOperator(restrict(grid, d), closure_stencil, r)
 
     # Create 1D IdentityTensors for each coordinate direction
-    one_d_grids = restrict.(Ref(grid), Tuple(1:dimension(grid)))
+    one_d_grids = restrict.(Ref(grid), Tuple(dims(grid)))
     Is = IdentityTensor{eltype(grid)}.(size.(one_d_grids))
 
     # Formulate the correct outer product sequence of the identity mappings and
--- a/src/SbpOperators/volumeops/inner_products/inner_product.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/SbpOperators/volumeops/inner_products/inner_product.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -18,7 +18,7 @@
 function inner_product(grid::EquidistantGrid, interior_weight, closure_weights)
     Hs = ()
 
-    for i ∈ 1:dimension(grid)
+    for i ∈ dims(grid)
         Hs = (Hs..., inner_product(restrict(grid, i), interior_weight, closure_weights))
     end
 
--- a/src/SbpOperators/volumeops/inner_products/inverse_inner_product.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/SbpOperators/volumeops/inner_products/inverse_inner_product.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -15,7 +15,7 @@
 function inverse_inner_product(grid::EquidistantGrid, interior_weight, closure_weights)
     H⁻¹s = ()
 
-    for i ∈ 1:dimension(grid)
+    for i ∈ dims(grid)
         H⁻¹s = (H⁻¹s..., inverse_inner_product(restrict(grid, i), interior_weight, closure_weights))
     end
 
--- a/src/SbpOperators/volumeops/laplace/laplace.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/SbpOperators/volumeops/laplace/laplace.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -48,7 +48,7 @@
 """
 function laplace(grid::EquidistantGrid, inner_stencil, closure_stencils)
     Δ = second_derivative(grid, inner_stencil, closure_stencils, 1)
-    for d = 2:dimension(grid)
+    for d = 2:ndims(grid)
         Δ += second_derivative(grid, inner_stencil, closure_stencils, d)
     end
     return Δ
--- a/src/SbpOperators/volumeops/volume_operator.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/src/SbpOperators/volumeops/volume_operator.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -15,7 +15,7 @@
     # Create 1D volume operator in along coordinate direction
     op = VolumeOperator(restrict(grid, direction), inner_stencil, closure_stencils, parity)
     # Create 1D IdentityTensors for each coordinate direction
-    one_d_grids = restrict.(Ref(grid), Tuple(1:dimension(grid)))
+    one_d_grids = restrict.(Ref(grid), Tuple(dims(grid)))
     Is = IdentityTensor{eltype(grid)}.(size.(one_d_grids))
     # Formulate the correct outer product sequence of the identity mappings and
     # the volume operator
--- a/test/Grids/EquidistantGrid_test.jl	Wed Apr 27 10:25:53 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-using Sbplib.Grids
-using Test
-using Sbplib.RegionIndices
-
-
-@testset "EquidistantGrid" begin
-    @test EquidistantGrid(4,0.0,1.0) isa EquidistantGrid
-    @test EquidistantGrid(4,0.0,8.0) isa EquidistantGrid
-    # constuctor
-    @test_throws DomainError EquidistantGrid(0,0.0,1.0)
-    @test_throws DomainError EquidistantGrid(1,1.0,1.0)
-    @test_throws DomainError EquidistantGrid(1,1.0,-1.0)
-    @test EquidistantGrid(4,0.0,1.0) == EquidistantGrid((4,),(0.0,),(1.0,))
-
-    @testset "Base" begin
-        @test eltype(EquidistantGrid(4,0.0,1.0)) == Float64
-        @test eltype(EquidistantGrid((4,3),(0,0),(1,3))) == Int
-        @test size(EquidistantGrid(4,0.0,1.0)) == (4,)
-        @test size(EquidistantGrid((5,3), (0.0,0.0), (2.0,1.0))) == (5,3)
-    end
-
-    # dimension
-    @test dimension(EquidistantGrid(4,0.0,1.0)) == 1
-    @test dimension(EquidistantGrid((5,3), (0.0,0.0), (2.0,1.0))) == 2
-
-    # spacing
-    @test [spacing(EquidistantGrid(4,0.0,1.0))...] ≈ [(1. /3,)...] atol=5e-13
-    @test [spacing(EquidistantGrid((5,3), (0.0,-1.0), (2.0,1.0)))...] ≈ [(0.5, 1.)...] atol=5e-13
-
-    # inverse_spacing
-    @test [inverse_spacing(EquidistantGrid(4,0.0,1.0))...] ≈ [(3.,)...] atol=5e-13
-    @test [inverse_spacing(EquidistantGrid((5,3), (0.0,-1.0), (2.0,1.0)))...] ≈ [(2, 1.)...] atol=5e-13
-
-    # points
-    g = EquidistantGrid((5,3), (-1.0,0.0), (0.0,7.11))
-    gp = points(g);
-    p = [(-1.,0.)      (-1.,7.11/2)   (-1.,7.11);
-         (-0.75,0.)    (-0.75,7.11/2) (-0.75,7.11);
-         (-0.5,0.)     (-0.5,7.11/2)  (-0.5,7.11);
-         (-0.25,0.)    (-0.25,7.11/2) (-0.25,7.11);
-         (0.,0.)       (0.,7.11/2)    (0.,7.11)]
-    for i ∈ eachindex(gp)
-        @test [gp[i]...] ≈ [p[i]...] atol=5e-13
-    end
-
-
-    @testset "getindex" begin
-        g = EquidistantGrid((5,3), (-1.0,0.0), (0.0,7.11))
-        @test g[1,1] == (-1.0,0.0)
-        @test g[1,3] == (-1.0,7.11)
-        @test g[5,1] == (0.0,0.0)
-        @test g[5,3] == (0.0,7.11)
-
-        @test g[4,2] == (-0.25,7.11/2)
-
-        @test g[CartesianIndex(1,3)] == (-1.0,7.11)
-    end
-
-    # restrict
-    g = EquidistantGrid((5,3), (0.0,0.0), (2.0,1.0))
-    @test restrict(g, 1) == EquidistantGrid(5,0.0,2.0)
-    @test restrict(g, 2) == EquidistantGrid(3,0.0,1.0)
-
-    g = EquidistantGrid((2,5,3), (0.0,0.0,0.0), (2.0,1.0,3.0))
-    @test restrict(g, 1) == EquidistantGrid(2,0.0,2.0)
-    @test restrict(g, 2) == EquidistantGrid(5,0.0,1.0)
-    @test restrict(g, 3) == EquidistantGrid(3,0.0,3.0)
-    @test restrict(g, 1:2) == EquidistantGrid((2,5),(0.0,0.0),(2.0,1.0))
-    @test restrict(g, 2:3) == EquidistantGrid((5,3),(0.0,0.0),(1.0,3.0))
-    @test restrict(g, [1,3]) == EquidistantGrid((2,3),(0.0,0.0),(2.0,3.0))
-    @test restrict(g, [2,1]) == EquidistantGrid((5,2),(0.0,0.0),(1.0,2.0))
-
-    @testset "boundary_identifiers" begin
-        g = EquidistantGrid((2,5,3), (0.0,0.0,0.0), (2.0,1.0,3.0))
-        bids = (CartesianBoundary{1,Lower}(),CartesianBoundary{1,Upper}(),
-                CartesianBoundary{2,Lower}(),CartesianBoundary{2,Upper}(),
-                CartesianBoundary{3,Lower}(),CartesianBoundary{3,Upper}())
-        @test boundary_identifiers(g) == bids
-        @inferred boundary_identifiers(g)
-    end
-
-    @testset "boundary_grid" begin
-            @testset "1D" begin
-                g = EquidistantGrid(5,0.0,2.0)
-                (id_l, id_r) = boundary_identifiers(g)
-                @test boundary_grid(g,id_l) == EquidistantGrid{Float64}()
-                @test boundary_grid(g,id_r) == EquidistantGrid{Float64}()
-                @test_throws DomainError boundary_grid(g,CartesianBoundary{2,Lower}())
-                @test_throws DomainError boundary_grid(g,CartesianBoundary{0,Lower}())
-            end
-            @testset "2D" begin
-                g = EquidistantGrid((5,3),(0.0,0.0),(1.0,3.0))
-                (id_w, id_e, id_s, id_n) = boundary_identifiers(g)
-                @test boundary_grid(g,id_w) == restrict(g,2)
-                @test boundary_grid(g,id_e) == restrict(g,2)
-                @test boundary_grid(g,id_s) == restrict(g,1)
-                @test boundary_grid(g,id_n) == restrict(g,1)
-                @test_throws DomainError boundary_grid(g,CartesianBoundary{4,Lower}())
-            end
-            @testset "3D" begin
-                g = EquidistantGrid((2,5,3), (0.0,0.0,0.0), (2.0,1.0,3.0))
-                (id_w, id_e,
-                 id_s, id_n,
-                 id_t, id_b) = boundary_identifiers(g)
-                @test boundary_grid(g,id_w) == restrict(g,[2,3])
-                @test boundary_grid(g,id_e) == restrict(g,[2,3])
-                @test boundary_grid(g,id_s) == restrict(g,[1,3])
-                @test boundary_grid(g,id_n) == restrict(g,[1,3])
-                @test boundary_grid(g,id_t) == restrict(g,[1,2])
-                @test boundary_grid(g,id_b) == restrict(g,[1,2])
-                @test_throws DomainError boundary_grid(g,CartesianBoundary{4,Lower}())
-            end
-    end
-
-    @testset "refine" begin
-        @test refine(EquidistantGrid{Float64}(), 1) == EquidistantGrid{Float64}()
-        @test refine(EquidistantGrid{Float64}(), 2) == EquidistantGrid{Float64}()
-
-        g = EquidistantGrid((10,5),(0.,1.),(2.,3.))
-        @test refine(g, 1) == g
-        @test refine(g, 2) == EquidistantGrid((19,9),(0.,1.),(2.,3.))
-        @test refine(g, 3) == EquidistantGrid((28,13),(0.,1.),(2.,3.))
-    end
-
-    @testset "coarsen" begin
-        @test coarsen(EquidistantGrid{Float64}(), 1) == EquidistantGrid{Float64}()
-        @test coarsen(EquidistantGrid{Float64}(), 2) == EquidistantGrid{Float64}()
-
-        g = EquidistantGrid((7,13),(0.,1.),(2.,3.))
-        @test coarsen(g, 1) == g
-        @test coarsen(g, 2) == EquidistantGrid((4,7),(0.,1.),(2.,3.))
-        @test coarsen(g, 3) == EquidistantGrid((3,5),(0.,1.),(2.,3.))
-
-        @test_throws DomainError(4, "Size minus 1 must be divisible by the ratio.") coarsen(g, 4) == EquidistantGrid((3,5),(0.,1.),(2.,3.))
-    end
-end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/Grids/equidistant_grid_test.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -0,0 +1,137 @@
+using Sbplib.Grids
+using Test
+using Sbplib.RegionIndices
+
+
+@testset "EquidistantGrid" begin
+    @test EquidistantGrid(4,0.0,1.0) isa EquidistantGrid
+    @test EquidistantGrid(4,0.0,8.0) isa EquidistantGrid
+    # constuctor
+    @test_throws DomainError EquidistantGrid(0,0.0,1.0)
+    @test_throws DomainError EquidistantGrid(1,1.0,1.0)
+    @test_throws DomainError EquidistantGrid(1,1.0,-1.0)
+    @test EquidistantGrid(4,0.0,1.0) == EquidistantGrid((4,),(0.0,),(1.0,))
+
+    @testset "Base" begin
+        @test eltype(EquidistantGrid(4,0.0,1.0)) == Float64
+        @test eltype(EquidistantGrid((4,3),(0,0),(1,3))) == Int
+        @test size(EquidistantGrid(4,0.0,1.0)) == (4,)
+        @test size(EquidistantGrid((5,3), (0.0,0.0), (2.0,1.0))) == (5,3)
+        @test ndims(EquidistantGrid(4,0.0,1.0)) == 1
+        @test ndims(EquidistantGrid((5,3), (0.0,0.0), (2.0,1.0))) == 2
+    end
+
+    @testset "spacing" begin
+        @test [spacing(EquidistantGrid(4,0.0,1.0))...] ≈ [(1. /3,)...] atol=5e-13
+        @test [spacing(EquidistantGrid((5,3), (0.0,-1.0), (2.0,1.0)))...] ≈ [(0.5, 1.)...] atol=5e-13
+    end
+
+    @testset "inverse_spacing" begin
+        @test [inverse_spacing(EquidistantGrid(4,0.0,1.0))...] ≈ [(3.,)...] atol=5e-13
+        @test [inverse_spacing(EquidistantGrid((5,3), (0.0,-1.0), (2.0,1.0)))...] ≈ [(2, 1.)...] atol=5e-13
+    end
+
+    @testset "points" begin
+        g = EquidistantGrid((5,3), (-1.0,0.0), (0.0,7.11))
+        gp = points(g);
+        p = [(-1.,0.)      (-1.,7.11/2)   (-1.,7.11);
+            (-0.75,0.)    (-0.75,7.11/2) (-0.75,7.11);
+            (-0.5,0.)     (-0.5,7.11/2)  (-0.5,7.11);
+            (-0.25,0.)    (-0.25,7.11/2) (-0.25,7.11);
+            (0.,0.)       (0.,7.11/2)    (0.,7.11)]
+        for i ∈ eachindex(gp)
+            @test [gp[i]...] ≈ [p[i]...] atol=5e-13
+        end
+    end
+
+    @testset "getindex" begin
+        g = EquidistantGrid((5,3), (-1.0,0.0), (0.0,7.11))
+        @test g[1,1] == (-1.0,0.0)
+        @test g[1,3] == (-1.0,7.11)
+        @test g[5,1] == (0.0,0.0)
+        @test g[5,3] == (0.0,7.11)
+
+        @test g[4,2] == (-0.25,7.11/2)
+
+        @test g[CartesianIndex(1,3)] == (-1.0,7.11)
+    end
+
+    @testset "restrict" begin
+        g = EquidistantGrid((5,3), (0.0,0.0), (2.0,1.0))
+        @test restrict(g, 1) == EquidistantGrid(5,0.0,2.0)
+        @test restrict(g, 2) == EquidistantGrid(3,0.0,1.0)
+
+        g = EquidistantGrid((2,5,3), (0.0,0.0,0.0), (2.0,1.0,3.0))
+        @test restrict(g, 1) == EquidistantGrid(2,0.0,2.0)
+        @test restrict(g, 2) == EquidistantGrid(5,0.0,1.0)
+        @test restrict(g, 3) == EquidistantGrid(3,0.0,3.0)
+        @test restrict(g, 1:2) == EquidistantGrid((2,5),(0.0,0.0),(2.0,1.0))
+        @test restrict(g, 2:3) == EquidistantGrid((5,3),(0.0,0.0),(1.0,3.0))
+        @test restrict(g, [1,3]) == EquidistantGrid((2,3),(0.0,0.0),(2.0,3.0))
+        @test restrict(g, [2,1]) == EquidistantGrid((5,2),(0.0,0.0),(1.0,2.0))
+    end
+
+    @testset "boundary_identifiers" begin
+        g = EquidistantGrid((2,5,3), (0.0,0.0,0.0), (2.0,1.0,3.0))
+        bids = (CartesianBoundary{1,Lower}(),CartesianBoundary{1,Upper}(),
+                CartesianBoundary{2,Lower}(),CartesianBoundary{2,Upper}(),
+                CartesianBoundary{3,Lower}(),CartesianBoundary{3,Upper}())
+        @test boundary_identifiers(g) == bids
+        @inferred boundary_identifiers(g)
+    end
+
+    @testset "boundary_grid" begin
+            @testset "1D" begin
+                g = EquidistantGrid(5,0.0,2.0)
+                (id_l, id_r) = boundary_identifiers(g)
+                @test boundary_grid(g,id_l) == EquidistantGrid{Float64}()
+                @test boundary_grid(g,id_r) == EquidistantGrid{Float64}()
+                @test_throws DomainError boundary_grid(g,CartesianBoundary{2,Lower}())
+                @test_throws DomainError boundary_grid(g,CartesianBoundary{0,Lower}())
+            end
+            @testset "2D" begin
+                g = EquidistantGrid((5,3),(0.0,0.0),(1.0,3.0))
+                (id_w, id_e, id_s, id_n) = boundary_identifiers(g)
+                @test boundary_grid(g,id_w) == restrict(g,2)
+                @test boundary_grid(g,id_e) == restrict(g,2)
+                @test boundary_grid(g,id_s) == restrict(g,1)
+                @test boundary_grid(g,id_n) == restrict(g,1)
+                @test_throws DomainError boundary_grid(g,CartesianBoundary{4,Lower}())
+            end
+            @testset "3D" begin
+                g = EquidistantGrid((2,5,3), (0.0,0.0,0.0), (2.0,1.0,3.0))
+                (id_w, id_e,
+                 id_s, id_n,
+                 id_t, id_b) = boundary_identifiers(g)
+                @test boundary_grid(g,id_w) == restrict(g,[2,3])
+                @test boundary_grid(g,id_e) == restrict(g,[2,3])
+                @test boundary_grid(g,id_s) == restrict(g,[1,3])
+                @test boundary_grid(g,id_n) == restrict(g,[1,3])
+                @test boundary_grid(g,id_t) == restrict(g,[1,2])
+                @test boundary_grid(g,id_b) == restrict(g,[1,2])
+                @test_throws DomainError boundary_grid(g,CartesianBoundary{4,Lower}())
+            end
+    end
+
+    @testset "refine" begin
+        @test refine(EquidistantGrid{Float64}(), 1) == EquidistantGrid{Float64}()
+        @test refine(EquidistantGrid{Float64}(), 2) == EquidistantGrid{Float64}()
+
+        g = EquidistantGrid((10,5),(0.,1.),(2.,3.))
+        @test refine(g, 1) == g
+        @test refine(g, 2) == EquidistantGrid((19,9),(0.,1.),(2.,3.))
+        @test refine(g, 3) == EquidistantGrid((28,13),(0.,1.),(2.,3.))
+    end
+
+    @testset "coarsen" begin
+        @test coarsen(EquidistantGrid{Float64}(), 1) == EquidistantGrid{Float64}()
+        @test coarsen(EquidistantGrid{Float64}(), 2) == EquidistantGrid{Float64}()
+
+        g = EquidistantGrid((7,13),(0.,1.),(2.,3.))
+        @test coarsen(g, 1) == g
+        @test coarsen(g, 2) == EquidistantGrid((4,7),(0.,1.),(2.,3.))
+        @test coarsen(g, 3) == EquidistantGrid((3,5),(0.,1.),(2.,3.))
+
+        @test_throws DomainError(4, "Size minus 1 must be divisible by the ratio.") coarsen(g, 4) == EquidistantGrid((3,5),(0.,1.),(2.,3.))
+    end
+end
--- a/test/LazyTensors/lazy_array_test.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/test/LazyTensors/lazy_array_test.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -67,11 +67,18 @@
     @test isa(v1 + v2, LazyArray)
     @test isa(v2 + v1, LazyArray)
     @test isa(v1 - v2, LazyArray)
-    @test isa(v2 - v1, LazyArray)
+    @test isa(v2 - v1, LazyArray)    
+    @test isa(v1 + s, LazyArray)
+    @test isa(s + v1, LazyArray)
+    @test isa(v1 - s, LazyArray)
+    @test isa(s - v1, LazyArray)
     for i ∈ eachindex(v2)
         @test (v1 + v2)[i] == (v2 + v1)[i] == r_add_v[i]
         @test (v1 - v2)[i] == -(v2 - v1)[i] == r_sub_v[i]
+        @test (v1 + s)[i] == (s + v1)[i] == r_add_s[i]
+        @test (v1 - s)[i] == -(s - v1)[i] == r_sub_s[i]
     end
+    
     @test_throws BoundsError (v1 + v2)[4]
     v2 = [1., 2, 3, 4]
     @test_throws DimensionMismatch v1 + v2
--- a/test/LazyTensors/lazy_tensor_operations_test.jl	Wed Apr 27 10:25:53 2022 +0200
+++ b/test/LazyTensors/lazy_tensor_operations_test.jl	Wed Oct 19 22:36:02 2022 +0200
@@ -181,6 +181,14 @@
 
     @test (Ã∘B̃*ComplexF64[1.,2.,3.,4.])[1] isa ComplexF64
     @test ((Ã∘B̃)'*ComplexF64[1.,2.])[1] isa ComplexF64
+
+    a = 2.
+    v = rand(3)
+    @test a*Ã isa TensorComposition
+    @test a*Ã == Ã*a
+    @test range_size(a*Ã) == range_size(Ã)
+    @test domain_size(a*Ã) == domain_size(Ã)
+    @test a*Ã*v == a.*A*v
 end
 
 
--- a/test/Manifest.toml	Wed Apr 27 10:25:53 2022 +0200
+++ b/test/Manifest.toml	Wed Oct 19 22:36:02 2022 +0200
@@ -1,10 +1,12 @@
 # This file is machine-generated - editing it directly is not advised
 
-julia_version = "1.7.1"
+julia_version = "1.8.2"
 manifest_format = "2.0"
+project_hash = "23260eda65ade7d11fffed313a68520d0bc053fc"
 
 [[deps.ArgTools]]
 uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
+version = "1.1.1"
 
 [[deps.Artifacts]]
 uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
@@ -20,25 +22,26 @@
 
 [[deps.ChainRulesCore]]
 deps = ["Compat", "LinearAlgebra", "SparseArrays"]
-git-tree-sha1 = "9950387274246d08af38f6eef8cb5480862a435f"
+git-tree-sha1 = "e7ff6cadf743c098e08fca25c91103ee4303c9bb"
 uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
-version = "1.14.0"
+version = "1.15.6"
 
 [[deps.ChangesOfVariables]]
 deps = ["ChainRulesCore", "LinearAlgebra", "Test"]
-git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1"
+git-tree-sha1 = "38f7a08f19d8810338d4f5085211c7dfa5d5bdd8"
 uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
-version = "0.1.2"
+version = "0.1.4"
 
 [[deps.Compat]]
-deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
-git-tree-sha1 = "96b0bc6c52df76506efc8a441c6cf1adcb1babc4"
+deps = ["Dates", "LinearAlgebra", "UUIDs"]
+git-tree-sha1 = "5856d3031cdb1f3b2b6340dfdc66b6d9a149a374"
 uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
-version = "3.42.0"
+version = "4.2.0"
 
 [[deps.CompilerSupportLibraries_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"
+version = "0.5.2+0"
 
 [[deps.Dates]]
 deps = ["Printf"]
@@ -49,15 +52,11 @@
 uuid = "ab62b9b5-e342-54a8-a765-a90f495de1a6"
 version = "1.2.0"
 
-[[deps.DelimitedFiles]]
-deps = ["Mmap"]
-uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"
-
 [[deps.DiffRules]]
 deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"]
-git-tree-sha1 = "dd933c4ef7b4c270aacd4eb88fa64c147492acf0"
+git-tree-sha1 = "992a23afdb109d0d2f8802a30cf5ae4b1fe7ea68"
 uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
-version = "1.10.0"
+version = "1.11.1"
 
 [[deps.Distributed]]
 deps = ["Random", "Serialization", "Sockets"]
@@ -65,13 +64,17 @@
 
 [[deps.DocStringExtensions]]
 deps = ["LibGit2"]
-git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b"
+git-tree-sha1 = "5158c2b41018c5f7eb1470d558127ac274eca0c9"
 uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
-version = "0.8.6"
+version = "0.9.1"
 
 [[deps.Downloads]]
-deps = ["ArgTools", "LibCURL", "NetworkOptions"]
+deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"]
 uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
+version = "1.6.0"
+
+[[deps.FileWatching]]
+uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"
 
 [[deps.Glob]]
 git-tree-sha1 = "4df9f7e06108728ebf00a0a11edee4b29a482bb2"
@@ -84,9 +87,9 @@
 
 [[deps.InverseFunctions]]
 deps = ["Test"]
-git-tree-sha1 = "91b5dcf362c5add98049e6c29ee756910b03051d"
+git-tree-sha1 = "49510dfcb407e572524ba94aeae2fced1f3feb0f"
 uuid = "3587e190-3f89-42d0-90ee-14403ec27112"
-version = "0.1.3"
+version = "0.1.8"
 
 [[deps.IrrationalConstants]]
 git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151"
@@ -108,10 +111,12 @@
 [[deps.LibCURL]]
 deps = ["LibCURL_jll", "MozillaCACerts_jll"]
 uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
+version = "0.6.3"
 
 [[deps.LibCURL_jll]]
 deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
 uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
+version = "7.84.0+0"
 
 [[deps.LibGit2]]
 deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
@@ -120,6 +125,7 @@
 [[deps.LibSSH2_jll]]
 deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
 uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
+version = "1.10.2+0"
 
 [[deps.Libdl]]
 uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
@@ -130,9 +136,9 @@
 
 [[deps.LogExpFunctions]]
 deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"]
-git-tree-sha1 = "58f25e56b706f95125dcb796f39e1fb01d913a71"
+git-tree-sha1 = "94d9c52ca447e23eac0c0f074effbcd38830deb5"
 uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
-version = "0.3.10"
+version = "0.3.18"
 
 [[deps.Logging]]
 uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
@@ -144,28 +150,34 @@
 [[deps.MbedTLS_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
+version = "2.28.0+0"
 
 [[deps.Mmap]]
 uuid = "a63ad114-7e13-5084-954f-fe012c677804"
 
 [[deps.MozillaCACerts_jll]]
 uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
+version = "2022.2.1"
 
 [[deps.NaNMath]]
-git-tree-sha1 = "737a5957f387b17e74d4ad2f440eb330b39a62c5"
+deps = ["OpenLibm_jll"]
+git-tree-sha1 = "a7c3d1da1189a1c2fe843a3bfa04d18d20eb3211"
 uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
-version = "1.0.0"
+version = "1.0.1"
 
 [[deps.NetworkOptions]]
 uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
+version = "1.2.0"
 
 [[deps.OpenBLAS_jll]]
 deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
 uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"
+version = "0.3.20+0"
 
 [[deps.OpenLibm_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
+version = "0.8.1+0"
 
 [[deps.OpenSpecFun_jll]]
 deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
@@ -175,19 +187,20 @@
 
 [[deps.Parsers]]
 deps = ["Dates"]
-git-tree-sha1 = "85b5da0fa43588c75bb1ff986493443f821c70b7"
+git-tree-sha1 = "3d5bf43e3e8b412656404ed9466f1dcbf7c50269"
 uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
-version = "2.2.3"
+version = "2.4.0"
 
 [[deps.Pkg]]
 deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
 uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
+version = "1.8.0"
 
 [[deps.Preferences]]
 deps = ["TOML"]
-git-tree-sha1 = "d3538e7f8a790dc8903519090857ef8e1283eecd"
+git-tree-sha1 = "47e5f437cc0e7ef2ce8406ce1e7e24d44915f88d"
 uuid = "21216c6a-2e73-6563-6e65-726566657250"
-version = "1.2.5"
+version = "1.3.0"
 
 [[deps.Printf]]
 deps = ["Unicode"]
@@ -213,14 +226,11 @@
 
 [[deps.SHA]]
 uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
+version = "0.7.0"
 
 [[deps.Serialization]]
 uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
 
-[[deps.SharedArrays]]
-deps = ["Distributed", "Mmap", "Random", "Serialization"]
-uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"
-
 [[deps.Sockets]]
 uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
 
@@ -230,9 +240,9 @@
 
 [[deps.SpecialFunctions]]
 deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
-git-tree-sha1 = "5ba658aeecaaf96923dce0da9e703bd1fe7666f9"
+git-tree-sha1 = "d75bda01f8c31ebb72df80a46c88b25d1c79c56d"
 uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
-version = "2.1.4"
+version = "2.1.7"
 
 [[deps.Statistics]]
 deps = ["LinearAlgebra", "SparseArrays"]
@@ -241,10 +251,12 @@
 [[deps.TOML]]
 deps = ["Dates"]
 uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
+version = "1.0.0"
 
 [[deps.Tar]]
 deps = ["ArgTools", "SHA"]
 uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
+version = "1.10.1"
 
 [[deps.Test]]
 deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
@@ -258,9 +270,9 @@
 
 [[deps.Tullio]]
 deps = ["ChainRulesCore", "DiffRules", "LinearAlgebra", "Requires"]
-git-tree-sha1 = "7830c974acc69437a3fee35dd7b510a74cbc862d"
+git-tree-sha1 = "7871a39eac745697ee512a87eeff06a048a7905b"
 uuid = "bc48ee85-29a4-5162-ae0b-a64e1601d4bc"
-version = "0.3.3"
+version = "0.3.5"
 
 [[deps.UUIDs]]
 deps = ["Random", "SHA"]
@@ -272,15 +284,19 @@
 [[deps.Zlib_jll]]
 deps = ["Libdl"]
 uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
+version = "1.2.12+3"
 
 [[deps.libblastrampoline_jll]]
 deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
 uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"
+version = "5.1.1+0"
 
 [[deps.nghttp2_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
+version = "1.48.0+0"
 
 [[deps.p7zip_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
+version = "17.4.0+0"