Skip to content

Commit b6a1ab8

Browse files
docs: add and update docstrings for analysis points and transformations
1 parent 8b42da2 commit b6a1ab8

File tree

1 file changed

+183
-58
lines changed

1 file changed

+183
-58
lines changed

src/systems/analysis_points.jl

+183-58
Original file line numberDiff line numberDiff line change
@@ -198,19 +198,23 @@ function modify_nested_subsystem(
198198

199199
# recursive helper function which does the searching and modification
200200
function _helper(sys::AbstractSystem, i::Int)
201-
# we reached past the end, so everything matched and
202-
# `sys` is the system to modify.
203201
if i > length(hierarchy)
202+
# we reached past the end, so everything matched and
203+
# `sys` is the system to modify.
204204
sys, vars = fn(sys)
205205
else
206+
# find the subsystem with the given name and error otherwise
206207
cur = hierarchy[i]
207208
idx = findfirst(subsys -> nameof(subsys) == cur, get_systems(sys))
208209
idx === nothing &&
209210
error("System $(join([nameof(root); hierarchy[1:i-1]], '.')) does not have a subsystem named $cur.")
210211

212+
# recurse into new subsystem
211213
newsys, vars = _helper(get_systems(sys)[idx], i + 1)
214+
# update this system with modified subsystem
212215
@set! sys.systems[idx] = newsys
213216
end
217+
# only namespace variables from inner systems
214218
if i != 1
215219
vars = ntuple(Val(length(vars))) do i
216220
renamespace(sys, vars[i])
@@ -270,6 +274,15 @@ end
270274

271275
#### PRIMITIVE TRANSFORMATIONS
272276

277+
const DOC_WILL_REMOVE_AP = """
278+
Note that this transformation will remove `ap`, causing any subsequent transformations \
279+
referring to it to fail.\
280+
"""
281+
282+
const DOC_ADDED_VARIABLE = """
283+
The added variable(s) will have a default of zero, of the appropriate type and size.\
284+
"""
285+
273286
"""
274287
$(TYPEDEF)
275288
@@ -278,11 +291,9 @@ it will add a new input variable which connects to the outputs of the analysis p
278291
`apply_transformation` returns the new input variable (if added) as the auxiliary
279292
information. The new input variable will have the name `Symbol(:d_, nameof(ap))`.
280293
281-
Note that this transformation will remove `ap`, causing any subsequent transformations
282-
referring to it to fail.
294+
$DOC_WILL_REMOVE_AP
283295
284-
The added variable, if present, will have a default of zero, of the appropriate type and
285-
size.
296+
$DOC_ADDED_VARIABLE
286297
287298
## Fields
288299
@@ -340,17 +351,15 @@ end
340351
$(TYPEDEF)
341352
342353
A transformation which returns the variable corresponding to the input of the analysis
343-
point.
344-
345-
`apply_transformation` returns the variable as auxiliary information.
354+
point. Does not modify the system.
346355
347356
## Fields
348357
349358
$(TYPEDFIELDS)
350359
"""
351360
struct GetInput <: AnalysisPointTransformation
352361
"""
353-
The analysis point to add the output to.
362+
The analysis point to get the input of.
354363
"""
355364
ap::AnalysisPoint
356365
end
@@ -380,15 +389,12 @@ the analysis point before connecting to the outputs. The new variable will have
380389
381390
If `with_output == true`, also creates an additional new variable which has the value
382391
provided to the outputs after the above modification. This new variable has the same name
383-
as the analysis point.
384-
385-
`apply_transformation` returns a 1-tuple of the perturbation variable if
386-
`with_output == false` and a 2-tuple of the perturbation variable and output variable if
387-
`with_output == true`.
392+
as the analysis point and will be the second variable in the tuple of new variables returned
393+
from `apply_transformation`.
388394
389-
Removes the analysis point `ap`, so any subsequent transformations requiring it will fail.
395+
$DOC_WILL_REMOVE_AP
390396
391-
The added variable(s) will have a default of zero, of the appropriate type and size.
397+
$DOC_ADDED_VARIABLE
392398
393399
## Fields
394400
@@ -454,17 +460,33 @@ function apply_transformation(tf::PerturbOutput, sys::AbstractSystem)
454460
end
455461

456462
"""
457-
$(TYPEDSIGNATURES)
463+
$(TYPEDEF)
458464
459465
A transformation which adds a variable named `name` to the system containing the analysis
460-
point `ap`. The added variable has the same type and size as the input of the analysis
461-
point.
466+
point `ap`. $DOC_ADDED_VARIABLE
467+
468+
# Fields
469+
470+
$(TYPEDFIELDS)
462471
"""
463472
struct AddVariable <: AnalysisPointTransformation
473+
"""
474+
The analysis point in the system to modify, and whose input should be used as the
475+
template for the new variable.
476+
"""
464477
ap::AnalysisPoint
478+
"""
479+
The name of the added variable.
480+
"""
465481
name::Symbol
466482
end
467483

484+
"""
485+
$(TYPEDSIGNATURES)
486+
487+
Add a new variable to the system containing analysis point `ap` with the same name as the
488+
analysis point.
489+
"""
468490
AddVariable(ap::AnalysisPoint) = AddVariable(ap, nameof(ap))
469491

470492
function apply_transformation(tf::AddVariable, sys::AbstractSystem)
@@ -494,26 +516,34 @@ end
494516
$(TYPEDSIGNATURES)
495517
496518
A transformation enable calculating the sensitivity function about the analysis point `ap`.
497-
`apply_transformation` returns a 2-tuple `du, u` as auxiliary information.
519+
The returned added variables are `(du, u)` where `du` is the perturbation added to the
520+
input, and `u` is the output after perturbation.
498521
499-
Removes the analysis point `ap`, so any subsequent transformations requiring it will fail.
522+
$DOC_WILL_REMOVE_AP
500523
501-
The added variables will have a default of zero, of the appropriate type and size.
524+
$DOC_ADDED_VARIABLE
502525
"""
503526
SensitivityTransform(ap::AnalysisPoint) = PerturbOutput(ap, true)
504527

505528
"""
506529
$(TYPEDEF)
507530
508531
A transformation to enable calculating the complementary sensitivity function about the
509-
analysis point `ap`. `apply_transformation` returns a 2-tuple `du, u` as auxiliary
510-
information.
532+
analysis point `ap`. The returned added variables are `(du, u)` where `du` is the
533+
perturbation added to the outputs and `u` is the input to the analysis point.
511534
512-
Removes the analysis point `ap`, so any subsequent transformations requiring it will fail.
535+
$DOC_WILL_REMOVE_AP
513536
514-
The added variables will have a default of zero, of the appropriate type and size.
537+
$DOC_ADDED_VARIABLE
538+
539+
# Fields
540+
541+
$(TYPEDFIELDS)
515542
"""
516543
struct ComplementarySensitivityTransform <: AnalysisPointTransformation
544+
"""
545+
The analysis point to modify.
546+
"""
517547
ap::AnalysisPoint
518548
end
519549

@@ -537,7 +567,25 @@ function apply_transformation(cst::ComplementarySensitivityTransform, sys::Abstr
537567
return sys, (du, u)
538568
end
539569

570+
"""
571+
$(TYPEDEF)
572+
573+
A transformation to enable calculating the loop transfer function about the analysis point
574+
`ap`. The returned added variables are `(du, u)` where `du` feeds into the outputs of `ap`
575+
and `u` is the input of `ap`.
576+
577+
$DOC_WILL_REMOVE_AP
578+
579+
$DOC_ADDED_VARIABLE
580+
581+
# Fields
582+
583+
$(TYPEDFIELDS)
584+
"""
540585
struct LoopTransferTransform <: AnalysisPointTransformation
586+
"""
587+
The analysis point to modify.
588+
"""
541589
ap::AnalysisPoint
542590
end
543591

@@ -547,15 +595,25 @@ function apply_transformation(tf::LoopTransferTransform, sys::AbstractSystem)
547595
return sys, (du, u)
548596
end
549597

550-
### TODO: Move these
598+
"""
599+
$(TYPEDSIGNATURES)
551600
601+
A utility function to get the "canonical" form of a list of analysis points. Always returns
602+
a list of values. Any value that cannot be turned into an `AnalysisPoint` (i.e. isn't
603+
already an `AnalysisPoint` or `Symbol`) is simply wrapped in an array.
604+
"""
552605
canonicalize_ap(ap::Symbol) = [AnalysisPoint(ap)]
553606
canonicalize_ap(ap::AnalysisPoint) = [ap]
554607
canonicalize_ap(ap) = [ap]
555608
function canonicalize_ap(aps::Vector)
556609
mapreduce(canonicalize_ap, vcat, aps; init = [])
557610
end
558611

612+
"""
613+
$(TYPEDSIGNATURES)
614+
615+
Given a list of analysis points, break the connection for each and set the output to zero.
616+
"""
559617
function handle_loop_openings(sys::AbstractSystem, aps)
560618
for ap in canonicalize_ap(aps)
561619
sys, (outvar,) = apply_transformation(Break(ap, true), sys)
@@ -568,63 +626,130 @@ function handle_loop_openings(sys::AbstractSystem, aps)
568626
return sys
569627
end
570628

571-
function get_sensitivity_function(
572-
sys::AbstractSystem, aps; system_modifier = identity, loop_openings = [], kwargs...)
629+
const DOC_LOOP_OPENINGS = """
630+
- `loop_openings`: A list of analysis points whose connections should be removed and
631+
the outputs set to zero as a part of the linear analysis.
632+
"""
633+
634+
const DOC_SYS_MODIFIER = """
635+
- `system_modifier`: A function taking the transformed system and applying any
636+
additional transformations, returning the modified system. The modified system
637+
is passed to `linearization_function`.
638+
"""
639+
"""
640+
$(TYPEDSIGNATURES)
641+
642+
Utility function for linear analyses that apply a transformation `transform`, which
643+
returns the added variables `(du, u)`, to each of the analysis points in `aps` and then
644+
calls `linearization_function` with all the `du`s as inputs and `u`s as outputs. Returns
645+
the linearization function and modified, simplified system.
646+
647+
# Keyword arguments
648+
649+
$DOC_LOOP_OPENINGS
650+
$DOC_SYS_MODIFIER
651+
652+
All other keyword arguments are forwarded to `linearization_function`.
653+
"""
654+
function get_linear_analysis_function(
655+
sys::AbstractSystem, transform, aps; system_modifier = identity, loop_openings = [], kwargs...)
573656
sys = handle_loop_openings(sys, loop_openings)
574657
aps = canonicalize_ap(aps)
575658
dus = []
576659
us = []
577660
for ap in aps
578-
sys, (du, u) = apply_transformation(SensitivityTransform(ap), sys)
661+
sys, (du, u) = apply_transformation(transform(ap), sys)
579662
push!(dus, du)
580663
push!(us, u)
581664
end
582665
linearization_function(system_modifier(sys), dus, us; kwargs...)
583666
end
584667

585-
function get_comp_sensitivity_function(
586-
sys::AbstractSystem, aps; system_modifier = identity, loop_openings = [], kwargs...)
587-
sys = handle_loop_openings(sys, loop_openings)
588-
aps = canonicalize_ap(aps)
589-
dus = []
590-
us = []
591-
for ap in aps
592-
sys, (du, u) = apply_transformation(ComplementarySensitivityTransform(ap), sys)
593-
push!(dus, du)
594-
push!(us, u)
595-
end
596-
linearization_function(system_modifier(sys), dus, us; kwargs...)
668+
"""
669+
$(TYPEDSIGNATURES)
670+
671+
Return the sensitivity function for the analysis point(s) `aps`, and the modified system
672+
simplified with the appropriate inputs and outputs.
673+
674+
# Keyword Arguments
675+
676+
$DOC_LOOP_OPENINGS
677+
$DOC_SYS_MODIFIER
678+
679+
All other keyword arguments are forwarded to `linearization_function`.
680+
"""
681+
function get_sensitivity_function(sys::AbstractSystem, aps; kwargs...)
682+
get_linear_analysis_function(sys, SensitivityTransform, aps; kwargs...)
597683
end
598684

599-
function get_looptransfer_function(
600-
sys, aps; system_modifier = identity, loop_openings = [], kwargs...)
601-
sys = handle_loop_openings(sys, loop_openings)
602-
aps = canonicalize_ap(aps)
603-
dus = []
604-
us = []
605-
for ap in aps
606-
sys, (du, u) = apply_transformation(LoopTransferTransform(ap), sys)
607-
push!(dus, du)
608-
push!(us, u)
609-
end
610-
linearization_function(system_modifier(sys), dus, us; kwargs...)
685+
"""
686+
$(TYPEDSIGNATURES)
687+
688+
Return the complementary sensitivity function for the analysis point(s) `aps`, and the
689+
modified system simplified with the appropriate inputs and outputs.
690+
691+
# Keyword Arguments
692+
693+
$DOC_LOOP_OPENINGS
694+
$DOC_SYS_MODIFIER
695+
696+
All other keyword arguments are forwarded to `linearization_function`.
697+
"""
698+
function get_comp_sensitivity_function(sys::AbstractSystem, aps; kwargs...)
699+
get_linear_analysis_function(sys, ComplementarySensitivityTransform, aps; kwargs...)
700+
end
701+
702+
"""
703+
$(TYPEDSIGNATURES)
704+
705+
Return the loop-transfer function for the analysis point(s) `aps`, and the modified
706+
system simplified with the appropriate inputs and outputs.
707+
708+
# Keyword Arguments
709+
710+
$DOC_LOOP_OPENINGS
711+
$DOC_SYS_MODIFIER
712+
713+
All other keyword arguments are forwarded to `linearization_function`.
714+
"""
715+
function get_looptransfer_function(sys::AbstractSystem, aps; kwargs...)
716+
get_linear_analysis_function(sys, LoopTransferTransform, aps; kwargs...)
611717
end
612718

613719
for f in [:get_sensitivity, :get_comp_sensitivity, :get_looptransfer]
720+
utility_fun = Symbol(f, :_function)
614721
@eval function $f(
615722
sys, ap, args...; loop_openings = [], system_modifier = identity, kwargs...)
616-
lin_fun, ssys = $(Symbol(f, :_function))(
723+
lin_fun, ssys = $(utility_fun)(
617724
sys, ap, args...; loop_openings, system_modifier, kwargs...)
618725
ModelingToolkit.linearize(ssys, lin_fun; kwargs...), ssys
619726
end
727+
@eval @doc """
728+
$(TYPEDSIGNATURES)
729+
730+
Call `$($utility_fun)` and perform the linearization. All keyword arguments are
731+
forwarded to `$($utility_fun)` and subsequently `linearize`.
732+
""" $f
620733
end
621734

622-
function open_loop(sys, ap::Union{Symbol, AnalysisPoint}; kwargs...)
735+
"""
736+
$(TYPEDSIGNATURES)
737+
738+
Apply `LoopTransferTransform` to the analysis point `ap` and return the
739+
result of `apply_transformation`.
740+
741+
# Keyword Arguments
742+
743+
- `system_modifier`: a function which takes the modified system and returns a new system
744+
with any required further modifications peformed.
745+
"""
746+
function open_loop(sys, ap::Union{Symbol, AnalysisPoint}; system_modifier = identity)
623747
if ap isa Symbol
624748
ap = AnalysisPoint(ap)
625749
end
626750
tf = LoopTransferTransform(ap)
627-
return apply_transformation(tf, sys)
751+
sys, vars = apply_transformation(tf, sys)
752+
return system_modifier(sys), vars
628753
end
629754

630755
function linearization_function(sys::AbstractSystem,

0 commit comments

Comments
 (0)