From 756d80dea9f1bf0e6662d4c86de988f6e2284a8d Mon Sep 17 00:00:00 2001
From: Venkateshprasad <32921645+ven-k@users.noreply.github.com>
Date: Wed, 2 Apr 2025 08:41:32 +0000
Subject: [PATCH 1/2] feat(mtkmodel): provision to specify the type of System

---
 docs/src/basics/MTKLanguage.md | 39 ++++++++++++++++++++++++++++------
 src/systems/model_parsing.jl   | 23 ++++++++++++++------
 test/model_parsing.jl          | 15 +++++++++++++
 3 files changed, 65 insertions(+), 12 deletions(-)

diff --git a/docs/src/basics/MTKLanguage.md b/docs/src/basics/MTKLanguage.md
index 2bcec99b6a..e91f2bcb67 100644
--- a/docs/src/basics/MTKLanguage.md
+++ b/docs/src/basics/MTKLanguage.md
@@ -16,8 +16,9 @@ equations.
 ### [Defining components with `@mtkmodel`](@id mtkmodel)
 
 `@mtkmodel` is a convenience macro to define components. It returns
-`ModelingToolkit.Model`, which includes a constructor that returns the ODESystem, a
-`structure` dictionary with metadata, and flag `isconnector` which is set to `false`.
+`ModelingToolkit.Model`, which includes a system constructor (`ODESystem` by
+default), a `structure` dictionary with metadata, and flag `isconnector` which is
+set to `false`.
 
 ### What can an MTK-Model definition have?
 
@@ -26,7 +27,7 @@ equations.
   - `@description`: for describing the whole system with a human-readable string
   - `@components`: for listing sub-components of the system
   - `@constants`: for declaring constants
-  - `@defaults`: for passing `defaults` to ODESystem
+  - `@defaults`: for passing `defaults` to the system
   - `@equations`: for the list of equations
   - `@extend`: for extending a base system and unpacking its unknowns
   - `@icon` : for embedding the model icon
@@ -196,7 +197,7 @@ getdefault(model_c3.model_a.k_array[2])
 #### `@defaults` begin block
 
   - Default values can be passed as pairs.
-  - This is equivalent to passing `defaults` argument to `ODESystem`.
+  - This is equivalent to passing `defaults` argument to the system.
 
 #### `@continuous_events` begin block
 
@@ -256,6 +257,32 @@ end
 
   - Any other Julia operations can be included with dedicated begin blocks.
 
+### Setting the type of system:
+
+By default `@mtkmodel` returns an ODESystem. Different types of system can be
+defined with the following syntax:
+
+```
+@mtkmodel ModelName::SystemType begin
+    ...
+end
+
+```
+
+Example:
+
+```@example mtkmodel-example
+@mtkmodel Float2Bool::DiscreteSystem begin
+    @variables begin
+        u(t)::Float64
+        y(t)::Bool
+    end
+    @equations begin
+        y ~ u != 0
+    end
+end
+```
+
 ## Connectors
 
 Connectors are special models that can be used to connect different components together.
@@ -270,7 +297,7 @@ MTK provides 3 distinct connectors:
 ### [Defining connectors with `@connector`](@id connector)
 
 `@connector` returns `ModelingToolkit.Model`. It includes a constructor that returns
-a connector ODESystem, a `structure` dictionary with metadata, and flag `isconnector`
+a connector system (`ODESystem` by default), a `structure` dictionary with metadata, and flag `isconnector`
 which is set to `true`.
 
 A simple connector can be defined with syntax similar to following example:
@@ -498,7 +525,7 @@ end
 
 ## Build structurally simplified models:
 
-`@mtkbuild` builds an instance of a component and returns a structurally simplied `ODESystem`.
+`@mtkbuild` builds an instance of a component and returns a structurally simplied system.
 
 ```julia
 @mtkbuild sys = CustomModel()
diff --git a/src/systems/model_parsing.jl b/src/systems/model_parsing.jl
index 4632c1b889..195b02118e 100644
--- a/src/systems/model_parsing.jl
+++ b/src/systems/model_parsing.jl
@@ -7,7 +7,7 @@ ModelingToolkit component or connector with metadata
 $(FIELDS)
 """
 struct Model{F, S}
-    """The constructor that returns ODESystem."""
+    """The constructor that returns System."""
     f::F
     """
     The dictionary with metadata like keyword arguments (:kwargs), base
@@ -29,8 +29,8 @@ Base.parentmodule(m::Model) = parentmodule(m.f)
 for f in (:connector, :mtkmodel)
     isconnector = f == :connector ? true : false
     @eval begin
-        macro $f(name::Symbol, body)
-            esc($(:_model_macro)(__module__, name, body, $isconnector))
+        macro $f(fullname::Union{Expr, Symbol}, body)
+            esc($(:_model_macro)(__module__, fullname, body, $isconnector))
         end
     end
 end
@@ -41,7 +41,16 @@ function flatten_equations(eqs::Vector{Union{Equation, Vector{Equation}}})
     foldl(flatten_equations, eqs; init = Equation[])
 end
 
-function _model_macro(mod, name, expr, isconnector)
+function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector)
+    if fullname isa Symbol
+        name, type = fullname, :System
+    else
+        if fullname.head == :(::)
+            name, type = fullname.args
+        else
+            error("`$fullname` is not a valid name.")
+        end
+    end
     exprs = Expr(:block)
     dict = Dict{Symbol, Any}(
         :constants => Dict{Symbol, Dict}(),
@@ -61,7 +70,9 @@ function _model_macro(mod, name, expr, isconnector)
 
     push!(exprs.args, :(variables = []))
     push!(exprs.args, :(parameters = []))
-    push!(exprs.args, :(systems = ODESystem[]))
+    # We build `System` by default; vectors can't be created for `System` as it is
+    # a function.
+    push!(exprs.args, :(systems = ModelingToolkit.AbstractSystem[]))
     push!(exprs.args, :(equations = Union{Equation, Vector{Equation}}[]))
     push!(exprs.args, :(defaults = Dict{Num, Union{Number, Symbol, Function}}()))
 
@@ -114,7 +125,7 @@ function _model_macro(mod, name, expr, isconnector)
     @inline pop_structure_dict!.(
         Ref(dict), [:constants, :defaults, :kwargs, :structural_parameters])
 
-    sys = :($ODESystem($(flatten_equations)(equations), $iv, variables, parameters;
+    sys = :($type($(flatten_equations)(equations), $iv, variables, parameters;
         name, description = $description, systems, gui_metadata = $gui_metadata, defaults))
 
     if length(ext) == 0
diff --git a/test/model_parsing.jl b/test/model_parsing.jl
index 62c19d2055..e8464707de 100644
--- a/test/model_parsing.jl
+++ b/test/model_parsing.jl
@@ -1011,3 +1011,18 @@ end
         @test any(isequal(u), vars)
     end
 end
+
+@testset "Specify the type of system" begin
+    @mtkmodel Float2Bool::DiscreteSystem begin
+        @variables begin
+            u(t)::Float64
+            y(t)::Bool
+        end
+        @equations begin
+            y ~ u != 0
+        end
+    end
+
+    @named sys = Float2Bool()
+    @test typeof(sys) == DiscreteSystem
+end

From 070659d488e4403724b6995306a70b36b43a25fe Mon Sep 17 00:00:00 2001
From: Venkateshprasad <32921645+ven-k@users.noreply.github.com>
Date: Fri, 4 Apr 2025 02:51:43 +0000
Subject: [PATCH 2/2] test: rename test to not use `System`

System is an exported function.
And now it is used to build ODESystem by default
---
 test/initializationsystem.jl | 4 ++--
 test/split_parameters.jl     | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/test/initializationsystem.jl b/test/initializationsystem.jl
index 0f40d4eaf1..4ade3481cb 100644
--- a/test/initializationsystem.jl
+++ b/test/initializationsystem.jl
@@ -216,7 +216,7 @@ end
     end
 end
 
-@mtkmodel System begin
+@mtkmodel HydraulicSystem begin
     @components begin
         res₁ = Orifice(p′ = 300e5)
         res₂ = Orifice(p′ = 0)
@@ -234,7 +234,7 @@ end
     end
 end
 
-@mtkbuild sys = System()
+@mtkbuild sys = HydraulicSystem()
 initprob = ModelingToolkit.InitializationProblem(sys, 0.0)
 conditions = getfield.(equations(initprob.f.sys), :rhs)
 
diff --git a/test/split_parameters.jl b/test/split_parameters.jl
index 1052f4ad27..18fdb49a48 100644
--- a/test/split_parameters.jl
+++ b/test/split_parameters.jl
@@ -285,7 +285,7 @@ end
         end
     end
 
-    @mtkmodel System begin
+    @mtkmodel ApexSystem begin
         @components begin
             subsys = SubSystem()
         end
@@ -300,7 +300,7 @@ end
         end
     end
 
-    @named sys = System()
+    @named sys = ApexSystem()
     sysref = complete(sys)
     sys2 = complete(sys; split = true, flatten = false)
     ps = Set(full_parameters(sys2))