From f15b38bf7b1ae6e2cb38c3d8409a2a034430b7c7 Mon Sep 17 00:00:00 2001 From: cmhyett Date: Tue, 2 Dec 2025 13:56:50 -0600 Subject: [PATCH 1/2] Simple bypass to allow APs to be unitless with unitful connections --- src/systems/unit_check.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/systems/unit_check.jl b/src/systems/unit_check.jl index acf7451065..1aad1afa45 100644 --- a/src/systems/unit_check.jl +++ b/src/systems/unit_check.jl @@ -213,6 +213,11 @@ function _validate(terms::Vector, labels::Vector{String}; info::String = "") valid end +function _validate(ap::AnalysisPoint; info::String = "") + conn_eq = connect(ap.input, ap.outputs) + return _validate(conn_eq, info=info) +end + function _validate(conn::Connection; info::String = "") valid = true syss = get_systems(conn) @@ -277,7 +282,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) From 4d7372a09bef3bcd367faa9e5ee677ebb7585987 Mon Sep 17 00:00:00 2001 From: cmhyett Date: Wed, 3 Dec 2025 11:08:46 -0600 Subject: [PATCH 2/2] Duplicating logic where necessary, adding tests. --- src/systems/unit_check.jl | 4 +-- src/systems/validation.jl | 9 ++++-- test/analysis_points.jl | 64 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/systems/unit_check.jl b/src/systems/unit_check.jl index 1aad1afa45..21ec01e094 100644 --- a/src/systems/unit_check.jl +++ b/src/systems/unit_check.jl @@ -214,8 +214,8 @@ function _validate(terms::Vector, labels::Vector{String}; info::String = "") end function _validate(ap::AnalysisPoint; info::String = "") - conn_eq = connect(ap.input, ap.outputs) - return _validate(conn_eq, info=info) + conn_eq = connect(ap.input, ap.outputs...) + return _validate(conn_eq.rhs, info=info) end function _validate(conn::Connection; info::String = "") diff --git a/src/systems/validation.jl b/src/systems/validation.jl index d416a02ea2..d93dfbd9a4 100644 --- a/src/systems/validation.jl +++ b/src/systems/validation.jl @@ -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 @@ -182,6 +182,11 @@ function _validate(terms::Vector, labels::Vector{String}; info::String = "") valid end +function _validate(ap::AnalysisPoint; info::String = "") + conn_eq = connect(ap.input, ap.outputs...) + return _validate(conn_eq.rhs, info=info) +end + function _validate(conn::Connection; info::String = "") valid = true syss = get_systems(conn) @@ -242,7 +247,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) diff --git a/test/analysis_points.jl b/test/analysis_points.jl index f718e7bc59..19ac888aa8 100644 --- a/test/analysis_points.jl +++ b/test/analysis_points.jl @@ -7,6 +7,70 @@ using ModelingToolkit: t_nounits as t, D_nounits as D, AnalysisPoint, AbstractSy import ModelingToolkit as MTK import ControlSystemsBase as CS using Symbolics: NAMESPACE_SEPARATOR +using Unitful + +@testset "AnalysisPoint is ignored when verifying units" begin + # no units first + @mtkmodel FirstOrderTest begin + @components begin + in = Blocks.Step() + fb = Blocks.Feedback() + fo = Blocks.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 MySquare 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 sq = MySquare() + @test sq isa System +end @testset "AnalysisPoint is lowered to `connect`" begin @named P = FirstOrder(k = 1, T = 1)