Skip to content

Commit 43d4994

Browse files
committed
fixes
1 parent ef221a9 commit 43d4994

File tree

2 files changed

+32
-78
lines changed

2 files changed

+32
-78
lines changed

src/woperator.jl

Lines changed: 18 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
abstract type AbstractWOperator{T} <: AbstractSciMLOperator{T}
1+
abstract type AbstractWOperator{T} <: AbstractSciMLOperator{T} end
22

33
struct StaticWOperator{isinv, T, F} <: AbstractWOperator{T}
44
W::T
@@ -8,9 +8,7 @@ struct StaticWOperator{isinv, T, F} <: AbstractWOperator{T}
88
isinv = n <= 7 # cutoff where LU has noticable overhead
99

1010
F = if isinv && callinv
11-
# this should be in ArrayInterface but can't be for silly reasons
12-
# doing to how StaticArrays and StaticArraysCore are split up
13-
StaticArrays.LU(LowerTriangular(W), UpperTriangular(W), SVector{n}(1:n))
11+
ArrayInterface.lu_instance(W)
1412
else
1513
lu(W, check = false)
1614
end
@@ -36,18 +34,10 @@ W = \\frac{1}{\\gamma}MM - J
3634
```
3735
3836
where `MM` is the mass matrix (a regular `AbstractMatrix` or a `UniformScaling`),
39-
`γ` is a real number proportional to the time step, and `J` is the Jacobian
40-
operator (must be a `AbstractSciMLOperator`). A `WOperator` can also be
41-
constructed using a `*DEFunction` directly as
42-
43-
WOperator(f,gamma)
44-
45-
`f` needs to have a jacobian and `jac_prototype`, but the prototype does not need
46-
to be a diffeq operator --- it will automatically be converted to one.
37+
`γ` is a real number, and `J` is the Jacobian operator (must be a `AbstractSciMLOperator`).
4738
4839
`WOperator` supports lazy `*` and `mul!` operations, the latter utilizing an
4940
internal cache (can be specified in the constructor; default to regular `Vector`).
50-
It supports all of `AbstractSciMLOperator`'s interface.
5141
"""
5242
mutable struct WOperator{IIP, T,
5343
MType,
@@ -64,50 +54,11 @@ mutable struct WOperator{IIP, T,
6454
jacvec::JV
6555

6656
function WOperator{IIP}(mass_matrix, gamma, J, u, jacvec = nothing) where {IIP}
67-
# TODO: there is definitely a missing interface.
68-
# Tentative interface: `has_concrete` and `concertize(A)`
69-
if J isa Union{Number, ScalarOperator}
70-
_concrete_form = -mass_matrix / gamma + convert(Number, J)
71-
_func_cache = nothing
72-
else
73-
AJ = J isa MatrixOperator ? convert(AbstractMatrix, J) : J
74-
if AJ isa AbstractMatrix
75-
mm = mass_matrix isa MatrixOperator ?
76-
convert(AbstractMatrix, mass_matrix) : mass_matrix
77-
if is_sparse(AJ)
78-
79-
# If gamma is zero, then it's just an initialization and we want to make sure
80-
# we get the right sparsity pattern. If gamma is not zero, then it's a case where
81-
# a new W is created (as part of an out-of-place solve) and thus the actual
82-
# values actually matter!
83-
#
84-
# Constant operators never refactorize so always use the correct values there
85-
# as well
86-
if gamma == 0 && !(J isa MatrixOperator && isconstant(J))
87-
# Workaround https://github.com/JuliaSparse/SparseArrays.jl/issues/190
88-
# Hopefully `rand()` does not match any value in the array (prob ~ 0, with a check)
89-
# Then `one` is required since gamma is zero
90-
# Otherwise this will not pick up the union sparsity pattern
91-
# But instead drop the runtime zeros (i.e. all values) of the AJ pattern!
92-
AJn = nonzeros(AJ)
93-
x = rand()
94-
@assert all(!isequal(x), AJn)
95-
96-
fill!(AJn, rand())
97-
_concrete_form = -mm / one(gamma) + AJ
98-
fill!(_concrete_form, false) # safety measure, throw singular error if not filled
99-
else
100-
_concrete_form = -mm / gamma + AJ
101-
end
102-
else
103-
_concrete_form = -mm / gamma + AJ
104-
end
105-
106-
else
107-
_concrete_form = nothing
108-
end
109-
_func_cache = zero(u)
110-
end
57+
AJ = J isa MatrixOperator ? convert(AbstractMatrix, J) : J
58+
mm = mass_matrix isa MatrixOperator ?
59+
convert(AbstractMatrix, mass_matrix) : mass_matrix
60+
_concrete_form = -mm / gamma + AJ
61+
_func_cache = zero(u)
11162
T = eltype(_concrete_form)
11263
MType = typeof(mass_matrix)
11364
GType = typeof(gamma)
@@ -116,52 +67,42 @@ mutable struct WOperator{IIP, T,
11667
C = typeof(_concrete_form)
11768
JV = typeof(jacvec)
11869
return new{IIP, T, MType, GType, JType, F, C, JV}(mass_matrix, gamma, J,
119-
_func_cache, _concrete_form,
120-
jacvec)
70+
_func_cache, _concrete_form, jacvec)
12171
end
12272

12373
function Base.copy(W::WOperator{IIP, T, MType, GType, JType, F, C, JV}) where {IIP, T, MType, GType, JType, F, C, JV}
12474
return new{IIP, T, MType, GType, JType, F, C, JV}(
12575
W.mass_matrix,
12676
W.gamma,
12777
W.J,
128-
W._func_cache === nothing ? nothing : copy(W._func_cache),
129-
W._concrete_form === nothing ? nothing : copy(W._concrete_form),
78+
copy(W._func_cache),
79+
copy(W._concrete_form),
13080
W.jacvec
13181
)
13282
end
13383
end
13484
Base.eltype(W::WOperator) = eltype(W.J)
13585

136-
# In WOperator update_coefficients!, accept both missing u/p/t and missing dtgamma and don't update them in that case.
86+
# In WOperator update_coefficients!, accept both missing u/p/t and missing gamma and don't update them in that case.
13787
# This helps support partial updating logic used with Newton solvers.
13888
function update_coefficients!(W::WOperator,
13989
u = nothing,
14090
p = nothing,
14191
t = nothing;
142-
dtgamma = nothing)
92+
gamma = nothing)
14393
if (u !== nothing) && (p !== nothing) && (t !== nothing)
14494
update_coefficients!(W.J, u, p, t)
14595
update_coefficients!(W.mass_matrix, u, p, t)
14696
!isnothing(W.jacvec) && update_coefficients!(W.jacvec, u, p, t)
14797
end
148-
dtgamma !== nothing && (W.gamma = dtgamma)
98+
gamma !== nothing && (W.gamma = gamma)
14999
W
150100
end
151101

152-
function update_coefficients!(J::UJacobianWrapper, u, p, t)
153-
J.p = p
154-
J.t = t
155-
end
156-
157102
function Base.convert(::Type{AbstractMatrix}, W::WOperator{IIP}) where {IIP}
158103
if !IIP
159104
# Allocating
160105
W._concrete_form = -W.mass_matrix / W.gamma + convert(AbstractMatrix, W.J)
161-
else
162-
# Non-allocating already updated
163-
#_W = W._concrete_form
164-
#jacobian2W!(_W, W.mass_matrix, W.gamma, W.J)
165106
end
166107
return W._concrete_form
167108
end
@@ -202,19 +143,18 @@ function LinearAlgebra.mul!(Y::AbstractVecOrMat, W::WOperator, B::AbstractVecOrM
202143
# Compute mass_matrix * B
203144
if isa(W.mass_matrix, UniformScaling)
204145
a = -W.mass_matrix.λ / W.gamma
205-
@.. broadcast=false Y=a*B
146+
@. Y=a*B
206147
else
207148
mul!(_vec(Y), W.mass_matrix, _vec(B))
208149
lmul!(-inv(W.gamma), Y)
209150
end
210151
# Compute J * B and add
211-
if W.jacvec !== nothing
212-
mul!(_vec(W._func_cache), W.jacvec, _vec(B))
213-
else
152+
if isnothing(W.jacvec)
214153
mul!(_vec(W._func_cache), W.J, _vec(B))
154+
else
155+
mul!(_vec(W._func_cache), W.jacvec, _vec(B))
215156
end
216157
_vec(Y) .+= _vec(W._func_cache)
217158
end
218159

219-
220160
has_concretization(::AbstractWOperator) = true

test/WOperator.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using SciMLOperators, LinearAlgebra
2+
using Random
3+
using Test
4+
5+
Random.seed!(0)
6+
@testset "WOperator" begin
7+
J = rand(12, 12)
8+
u = rand(12)
9+
M = I(12)
10+
gamma = 1/123
11+
W = WOperator{true}(M, gamma, J, u)
12+
13+
@test convert(AbstractMatrix, W) J - M/gamma
14+
end

0 commit comments

Comments
 (0)