Skip to content

Commit b3fe4e7

Browse files
committed
methods: define and use function withUnit to enforce correct units
There might still be a few places where units need to be enforced, since comparing quantities and pure numbers does not work, and my manual tests have just not hit those branches yet.
1 parent a1bfb2b commit b3fe4e7

File tree

1 file changed

+48
-17
lines changed

1 file changed

+48
-17
lines changed

src/methods.jl

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -259,13 +259,10 @@ function _compute_estimate(
259259
# If we substitute `T.(coefs)` in the expression below, then allocations occur. We
260260
# therefore perform the broadcasting first. See
261261
# https://github.com/JuliaLang/julia/issues/39151.
262-
_coefs = T.(coefs)
263-
# NOTE the denominator: while doing T(step)^Q should technically be possible and correct,
264-
# without flipping the order of ^ Q and T(), the current code crashes in _limit_step
265-
# because of dimension mismatch. However, the output now has wrong units.
266262
#
267-
# TODO: fix the output units. The numerical value is correct in a simple test.
268-
return sum(fs .* _coefs) ./ T(step ^ Q)
263+
# We strip units because the estimate coefficients are just weights for values of f.
264+
_coefs = ustrip(T.(coefs))
265+
return sum(fs .* _coefs) ./ T(step) ^ Q
269266
end
270267

271268
# Check the method and derivative orders for consistency.
@@ -361,18 +358,27 @@ estimate of the derivative.
361358
function estimate_step(
362359
m::UnadaptedFiniteDifferenceMethod, f::TF, x::T,
363360
) where {TF,T<:Number}
364-
step, acc = _compute_step_acc_default(m, x)
361+
step, acc = withUnit.(
362+
unit(x),
363+
_compute_step_acc_default(m, x) .* unit(x)
364+
)
365365
return _limit_step(m, x, step, acc)
366366
end
367367
function estimate_step(
368368
m::AdaptedFiniteDifferenceMethod{P,Q}, f::TF, x::T,
369369
) where {P,Q,TF,T<:Number}
370-
∇f_magnitude, f_magnitude = _estimate_magnitudes(m.bound_estimator, f, x)
371-
if ∇f_magnitude == 0.0 || f_magnitude == 0.0
372-
step, acc = _compute_step_acc_default(m, x)
373-
else
374-
step, acc = _compute_step_acc(m, ∇f_magnitude, eps(f_magnitude))
375-
end
370+
@show ∇f_magnitude, f_magnitude = _estimate_magnitudes(m.bound_estimator, f, x)
371+
step, acc = withUnit.(
372+
(
373+
unit(x),
374+
unit(f |> eltype) / unit(x) ^ Q
375+
),
376+
if ∇f_magnitude == 0.0 || f_magnitude == 0.0
377+
_compute_step_acc_default(m, x)
378+
else
379+
_compute_step_acc(m, ∇f_magnitude, eps(f_magnitude))
380+
end
381+
)
376382
return _limit_step(m, x, step, acc)
377383
end
378384

@@ -413,19 +419,26 @@ end
413419
function _limit_step(
414420
m::FiniteDifferenceMethod, x::T, step::Number, acc::Number,
415421
) where {T<:Number}
422+
xunit = unit(x)
416423
# First, limit the step size based on the maximum range.
417-
step_max = m.max_range / maximum(abs.(m.grid))
424+
step_max = withUnit(
425+
xunit,
426+
m.max_range / maximum(abs.(m.grid))
427+
)
418428
if step > step_max
419429
step = step_max
420-
acc = NaN
430+
acc = withUnit(xunit,NaN)
421431
end
422432
# Second, prevent very large step sizes, which can occur for high-order methods or
423433
# slowly-varying functions.
424-
step_default, _ = _compute_step_acc_default(m, x)
434+
step_default, _ = withUnit.(
435+
xunit,
436+
_compute_step_acc_default(m, x)
437+
)
425438
step_max_default = 1000step_default
426439
if step > step_max_default
427440
step = step_max_default
428-
acc = NaN
441+
acc = withUnit(xunit,NaN)
429442
end
430443
return step, acc
431444
end
@@ -597,3 +610,21 @@ function extrapolate_fdm(
597610
kw_args...
598611
)
599612
end
613+
614+
"""
615+
Attaches a given unit to a given value, if it is dimensionless.
616+
If the value is not dimensionless, attempts a conversion to the given unit.
617+
"""
618+
function withUnit(targetUnit, value)
619+
620+
if Unitful.dimension(value) == Unitful.NoDims
621+
622+
value .* targetUnit
623+
624+
else
625+
626+
Unitful.uconvert(targetUnit, value)
627+
628+
end # if
629+
630+
end # function

0 commit comments

Comments
 (0)