Подкомпоненты и наследование в декларативном языке Engee
Страница в процессе разработки. |
В этой статье разберем, как в декларативном языке Engee можно строить более сложные модели за счет повторного использования кода: наследования от существующих компонентов и добавления подкомпонентов. Эти механизмы позволяют организовывать иерархию элементов, делать модели переиспользуемыми и более компактными.
Наследование компонентов
Иногда новый компонент очень похож на уже существующий, и нет смысла переписывать все заново. Для этого в декларативном языке Engee используется конструкция @extend
, которая позволяет наследовать переменные и уравнения из другого физического компонента.
@extend v, i = branch = Branch(i = 0, v = 0) # 1
@extend v, i = branch = Branch() # 2
@extend i = branch = Branch() # 3
@extend v = branch = Branch(i = 0.0) # 4
@extend v = branch = Branch(i = 0.0) # 5 - только если Branch написан через @engeemodel
@extend Branch() # 6 - только если Branch написан через @engeemodel
@extend Branch(i = 0) # 7 - только если Branch написан через @engeemodel
Здесь показаны разные варианты наследования. Общий формат:
-
Слева (
v, i
) указываются имена переменных, которые мы хотим извлечь из родительского компонента; -
branch = Branch(…)
— это создание экземпляра родительского компонента, из которого берутся переменные; -
Если переменные не извлечь, они останутся скрытыми и использоваться не смогут.
Применять @extend можно только один раз внутри компонента.
|
Особенности наследования:
-
Все переменные/параметры, которые должны отображаться в интерфейсе, нужно обязательно извлечь через
@extend
. Иначе они будут скрыты. -
В коде расширяющего компонента нужно обязательно передать все параметры, которые есть у родителя, если они имеют
gui = Modify
.
Ошибки при наследовании:
Если не извлечь нужные переменные, то в коде можно случайно получить неверные значения без ошибки. Например:
@engeemodel BV begin
@extend v = branch = Branch(i = 0.0, v = 0.0) # переменная i не извлечена
@variables begin
a = i + 5
end
end
Ошибки компиляции не будет, но i
в выражении окажется равной 0 (значение по умолчанию), что приведет к некорректной работе модели.
Подкомпоненты
Подкомпоненты — это компоненты, которые мы встраиваем внутрь других физических компонентов. Они создаются с помощью секции @components
.
@components begin
diode = Diode(v_forward = 0.6, R_on = 0.3, G_off = 1e-8)
capacitor = Capacitor(C = 1e-4)
end
Здесь в новый компонент добавлены два подкомпонента: диод и конденсатор.
-
В аргументах конструктора подкомпонента можно сразу задать параметры (
v_forward
,R_on
,C
и т. д.). -
Если подкомпонент объявлен через
@engeemodel
, то единицы измерения учитываются автоматически.
Если подкомпонент написан на императивном языке (через ModelingToolkit.jl), то передавать параметры и выражения нужно через функцию default() , чтобы значения автоматически переводились в систему СИ.
|
Пример с передачей значений
@engeemodel A begin
@variables begin
a = 1
b[:] = [1, 2]
end
@parameters begin
c = 3
d[:] = [3, 4]
end
@equations begin
a^2 ~ 2
b[1] * b[2] ~ 5
b[1]^2 ~ 12
end
end
@engeemodel B begin
@components begin
a1 = A(a = 2, b = [3, 4.0], c = 1, d = [5, 6])
a2 = A(a = e, b = f*2, c = sin(e), d = f .+ 2)
# нельзя передавать в качестве value символические массивы или выражения на их основе
a3 = A(d = (value = f, priority = "high"))
end
@parameters begin
e = 3
f[:] = [3,4]
end
end
В этом примере видно:
-
В компонент
A
передаются параметры и переменные разными способами (числа, выражения, массивы). -
Символические массивы нельзя передавать напрямую через
NamedTuple
. -
Для таких случаев можно использовать
default()
, чтобы правильно подставить значение.
Массивы подкомпонентов
Подкомпоненты можно задавать не только по одному, но и массивами.
@components begin
diodes = [Diode() for i in 1:5]
capacitors = [Capacitor() for i in 1:5]
end
Особенности:
-
Обращение к подкомпонентам выполняется как к обычным массивам Julia. Пример:
connect(diode[1].p, capacitor[3].p)
. -
Имена элементов для внешнего использования будут вида
diode_1
,diode_2
, … иcapacitor_1
,capacitor_2
, …
Это удобно, если нужно подключить сразу группу одинаковых элементов (например, несколько диодов или конденсаторов).
Выбор между наследованием и подкомпонентами
Наследование и подкомпоненты — это разные подходы для организации моделей. Чтобы было проще выбрать, сравним их в таблице:
Подход | Когда использовать | Особенности и ограничения |
---|---|---|
Наследование ( |
Когда новый компонент является «расширением» или «вариацией» существующего, и нужно добавить немного нового функционала. |
|
Подкомпоненты ( |
Когда новый компонент строится как комбинация нескольких других компонентов. |
|
Краткие рекомендации
-
Используйте
@extend
, когда нужно слегка расширить готовый компонент. -
Всегда извлекайте все переменные, которые планируете использовать, иначе получите значения по умолчанию.
-
Для подкомпонентов, написанных на ModelingToolkit.jl, используйте
default()
. -
Для однотипных элементов лучше задавать массивы подкомпонентов, чем копировать код.