Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/systems/unit_check.jl
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ function _validate(terms::Vector, labels::Vector{String}; info::String = "")
valid
end

function _validate(ap::AnalysisPoint; info::String = "")
is_valid = false
if (ap.outputs == nothing)
is_valid = true
else
conn_eq = connect(ap.input, ap.outputs...)
is_valid = _validate(conn_eq.rhs, info=info)
end
return is_valid
end

function _validate(conn::Connection; info::String = "")
valid = true
syss = get_systems(conn)
Expand Down Expand Up @@ -277,7 +288,7 @@ function validate(jumps::Vector{JumpType}, t::Symbolic)
end

function validate(eq::Union{Inequality, Equation}; info::String = "")
if typeof(eq.lhs) == Connection
if typeof(eq.lhs) <: Union{Connection, AnalysisPoint}
_validate(eq.rhs; info)
else
_validate([eq.lhs, eq.rhs], ["left", "right"]; info)
Expand Down
15 changes: 13 additions & 2 deletions src/systems/validation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module UnitfulUnitCheck

using ..ModelingToolkit, Symbolics, SciMLBase, Unitful, RecursiveArrayTools
using ..ModelingToolkit: ValidationError,
ModelingToolkit, Connection, instream, JumpType, VariableUnit,
ModelingToolkit, Connection, instream, JumpType, VariableUnit, AnalysisPoint,
get_systems,
Conditional, Comparison
using JumpProcesses: MassActionJump, ConstantRateJump, VariableRateJump
Expand Down Expand Up @@ -182,6 +182,17 @@ function _validate(terms::Vector, labels::Vector{String}; info::String = "")
valid
end

function _validate(ap::AnalysisPoint; info::String = "")
is_valid = false
if (ap.outputs == nothing)
is_valid = true
else
conn_eq = connect(ap.input, ap.outputs...)
is_valid = _validate(conn_eq.rhs, info=info)
end
return is_valid
end

function _validate(conn::Connection; info::String = "")
valid = true
syss = get_systems(conn)
Expand Down Expand Up @@ -242,7 +253,7 @@ function validate(jumps::Vector{JumpType}, t::Symbolic)
end

function validate(eq::MT.Equation; info::String = "")
if typeof(eq.lhs) == Connection
if typeof(eq.lhs) <: Union{AnalysisPoint, Connection}
_validate(eq.rhs; info)
else
_validate([eq.lhs, eq.rhs], ["left", "right"]; info)
Expand Down
110 changes: 97 additions & 13 deletions test/analysis_points.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,100 @@
using ModelingToolkit, ModelingToolkitStandardLibrary.Blocks, ControlSystemsBase
using ModelingToolkitStandardLibrary.Mechanical.Rotational
using ModelingToolkitStandardLibrary.Blocks
using OrdinaryDiffEq, LinearAlgebra
using Test
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D, AnalysisPoint, AbstractSystem
import ModelingToolkit as MTK
using ModelingToolkitStandardLibrary
using ModelingToolkitStandardLibrary.Blocks
using ModelingToolkitStandardLibrary.Mechanical.Rotational
using ControlSystemsBase
import ControlSystemsBase as CS
using OrdinaryDiffEq, LinearAlgebra
using Test
using Symbolics: NAMESPACE_SEPARATOR
using Unitful

@testset "AnalysisPoint is ignored when verifying units" begin
# no units first
@mtkmodel FirstOrderTest begin
@components begin
in = Step()
fb = Feedback()
fo = SecondOrder(k = 1, w = 1, d = 0.1)
end
@equations begin
connect(in.output, :u, fb.input1)
connect(fb.output, :e, fo.input)
connect(fo.output, :y, fb.input2)
end
end
@named model = FirstOrderTest()
@test model isa System

@connector function UnitfulOutput(; name)
vars = @variables begin
u(t), [unit=u"m", output=true]
end
return System(Equation[], t, vars, []; name)
end
@connector function UnitfulInput(; name)
vars = @variables begin
u(t), [unit=u"m", input=true]
end
return System(Equation[], t, vars, []; name)
end
@component function UnitfulBlock(; name)
pars = @parameters begin
offset, [unit=u"m"]
start_time
height, [unit=u"m"]
duration
end
systems = @named begin
output = UnitfulOutput()
end
eqs = [
output.u ~ offset + height*(0.5 + (1/pi)*atan(1e5*(t - start_time)))
]
return System(eqs, t, [], pars; systems, name)
end
@mtkmodel TestAPAroundUnits begin
@components begin
input = UnitfulInput()
end
@variables begin
output(t), [output=true, unit=u"m^2"]
end
@components begin
ub = UnitfulBlock()
end
@equations begin
connect(ub.output, :ap, input)
output ~ input.u^2
end
end
@named sys = TestAPAroundUnits()
@test sys isa System

@mtkmodel TestAPWithNoOutputs begin
@components begin
input = UnitfulInput()
end
@variables begin
output(t), [output=true, unit=u"m^2"]
end
@components begin
ub = UnitfulBlock()
end
@equations begin
connect(ub.output, :ap, input)
output ~ input.u^2
end
end
@named sys2 = TestAPWithNoOutputs()
@test sys2 isa System
end

@testset "AnalysisPoint is lowered to `connect`" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = -1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = -1)

ap = AnalysisPoint(:plant_input)
eqs = [connect(P.output, C.input)
Expand All @@ -30,7 +114,7 @@ end

@testset "Inverse causality throws a warning" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = -1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = -1)

ap = AnalysisPoint(:plant_input)
@test_warn ["1-th argument", "plant_input", "not a output"] connect(
Expand All @@ -41,7 +125,7 @@ end
# also tests `connect(input, name::Symbol, outputs...)` syntax
@testset "AnalysisPoint is accessible via `getproperty`" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = -1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = -1)

eqs = [connect(P.output, C.input), connect(C.output, :plant_input, P.input)]
sys_ap = System(eqs, t, systems = [P, C], name = :hej)
Expand All @@ -61,7 +145,7 @@ end
### Ported from MTKStdlib

@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = -1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = -1)

ap = AnalysisPoint(:plant_input)
eqs = [connect(P.output, C.input), connect(C.output, ap, P.input)]
Expand Down Expand Up @@ -266,7 +350,7 @@ end

@testset "Duplicate `connect` statements across subsystems with AP transforms - standard `connect`" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = 1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = 1)
@named add = Blocks.Add(k2 = -1)

eqs = [connect(P.output, :plant_output, add.input2)
Expand Down Expand Up @@ -302,7 +386,7 @@ end

@testset "Duplicate `connect` statements across subsystems with AP transforms - causal variable `connect`" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = 1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = 1)
@named add = Blocks.Add(k2 = -1)

eqs = [connect(P.output.u, :plant_output, add.input2.u)
Expand Down Expand Up @@ -338,7 +422,7 @@ end

@testset "Duplicate `connect` statements across subsystems with AP transforms - mixed `connect`" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = 1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = 1)
@named add = Blocks.Add(k2 = -1)

eqs = [connect(P.output.u, :plant_output, add.input2.u)
Expand Down Expand Up @@ -460,7 +544,7 @@ end

@testset "multiple analysis points" begin
@named P = FirstOrder(k = 1, T = 1)
@named C = Gain(; k = 1)
@named C = ModelingToolkitStandardLibrary.Blocks.Gain(; k = 1)
@named add = Blocks.Add(k2 = -1)

eqs = [connect(P.output, :plant_output, add.input2)
Expand Down
Loading