|
1 | 1 | Base.:*(x::Union{Num,Symbolic},y::Unitful.AbstractQuantity) = x * y
|
2 | 2 |
|
3 |
| -instantiate(x::Sym{Real}) = 1.0 |
4 |
| -instantiate(x::Symbolic) = oneunit(1*ModelingToolkit.vartype(x)) |
5 |
| -function instantiate(x::Num) |
6 |
| - x = value(x) |
7 |
| - if operation(x) isa Sym |
8 |
| - return instantiate(operation(x)) |
9 |
| - elseif operation(x) isa Differential |
10 |
| - instantiate(arguments(x)[1])/instantiate(arguments(x)[1].args[1]) |
| 3 | + |
| 4 | +function vartype(x::Symbolic) |
| 5 | + if !(x.metadata isa Nothing) |
| 6 | + return haskey(x.metadata,VariableUnit) ? x.metadata[VariableUnit] : 1.0 |
| 7 | + end |
| 8 | + 1.0 |
| 9 | +end |
| 10 | +vartype(x::Num) = vartype(value(x)) |
| 11 | + |
| 12 | +instantiate(x) = 1.0 |
| 13 | +instantiate(x::Num) = instantiate(value(x)) |
| 14 | +function instantiate(x::Symbolic) |
| 15 | + vx = value(x) |
| 16 | + if vx isa Sym || operation(vx) isa Sym |
| 17 | + return oneunit(1 * ModelingToolkit.vartype(x)) |
| 18 | + elseif operation(vx) isa Differential |
| 19 | + return instantiate(arguments(vx)[1]) / instantiate(arguments(arguments(vx)[1])[1]) |
| 20 | + elseif vx isa Pow |
| 21 | + pargs = arguments(vx) |
| 22 | + base,expon = instantiate.(pargs) |
| 23 | + uconvert(NoUnits, expon) # This acts as an assertion |
| 24 | + return base == 1.0 ? 1.0 : operation(vx)(base, pargs[2]) |
| 25 | + elseif vx isa Add # Cannot simply add the units b/c they may differ in magnitude (eg, kg vs g) |
| 26 | + terms = instantiate.(arguments(vx)) |
| 27 | + firstunit = unit(terms[1]) |
| 28 | + @assert all(map(x -> ustrip(firstunit, x) == 1, terms[2:end])) |
| 29 | + return 1.0 * firstunit |
11 | 30 | else
|
12 |
| - operation(x)(instantiate.(arguments(x))...) |
| 31 | + return oneunit(operation(vx)(instantiate.(arguments(vx))...)) |
13 | 32 | end
|
14 | 33 | end
|
15 | 34 |
|
16 |
| -function validate(eq::ModelingToolkit.Equation) |
| 35 | +function validate(eq::ModelingToolkit.Equation; eqnum = 1) |
| 36 | + lhs = rhs = nothing |
17 | 37 | try
|
18 |
| - return typeof(instantiate(eq.lhs)) == typeof(instantiate(eq.rhs)) |
19 |
| - catch |
20 |
| - return false |
| 38 | + lhs = instantiate(eq.lhs) |
| 39 | + catch err |
| 40 | + if err isa Unitful.DimensionError |
| 41 | + @warn("In left-hand side of eq. #$eqnum: $(eq.lhs), $(err.x) and $(err.y) are not dimensionally compatible.") |
| 42 | + elseif err isa MethodError |
| 43 | + @warn("In right-hand side of eq. #$eqnum: $(err.f) doesn't accept $(err.args).") |
| 44 | + else |
| 45 | + rethrow() |
| 46 | + end |
21 | 47 | end
|
| 48 | + try |
| 49 | + rhs = instantiate(eq.rhs) |
| 50 | + catch err |
| 51 | + if err isa Unitful.DimensionError |
| 52 | + @warn("In right-hand side of eq. #$eqnum: $(eq.rhs), $(err.x) and $(err.y) are not dimensionally compatible.") |
| 53 | + elseif err isa MethodError |
| 54 | + @warn("In right-hand side of eq. #$eqnum: $(err.f) doesn't accept $(err.args).") |
| 55 | + else |
| 56 | + rethrow() |
| 57 | + end |
| 58 | + end |
| 59 | + if (rhs !== nothing) && (lhs !== nothing) |
| 60 | + if !isequal(lhs, rhs) |
| 61 | + @warn("In eq. #$eqnum, left-side units ($lhs) and right-side units ($rhs) don't match.") |
| 62 | + end |
| 63 | + end |
| 64 | + (rhs !== nothing) && (lhs !== nothing) && isequal(lhs, rhs) |
22 | 65 | end
|
23 | 66 |
|
24 |
| -function validate(sys::AbstractODESystem) |
25 |
| - all(validate.(equations(sys))) |
| 67 | +function validate(eqs::Vector{ModelingToolkit.Equation}) |
| 68 | + correct = [validate(eqs[idx],eqnum=idx) for idx in 1:length(eqs)] |
| 69 | + all(correct) || throw(ArgumentError("Invalid equations, see warnings for details.")) |
26 | 70 | end
|
| 71 | + |
| 72 | +validate(sys::AbstractODESystem) = validate(equations(sys)) |
0 commit comments