Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
1 change: 1 addition & 0 deletions docs/src/API/model_building.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ change_independent_variable
add_accumulations
noise_to_brownians
convert_system_indepvar
ModelingToolkit.subset_tunables
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To stay on theme with #3884, let's mark this function using @public near the bottom of src/ModelingToolkit.jl?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 8c8dbf8

```

## Hybrid systems
Expand Down
39 changes: 39 additions & 0 deletions src/parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,42 @@ function split_parameters_by_type(ps)
end
end
end

"""
$(TYPEDSIGNATURES)

Change the tunable parameters of a system to a new set of tunables.

The new tunable parameters must be a subset of the current tunables as discovered by [`tunable_parameters`](@ref).
The remaining parameters will be set as constants in the system.
"""
function subset_tunables(sys, new_tunables)
if !iscomplete(sys)
throw(ArgumentError("System must be `complete` before changing tunables."))
end
if !is_split(sys)
throw(ArgumentError("Tunable parameters can only be changed for split systems."))
end

cur_tunables = tunable_parameters(sys, parameters(sys))
diff_params = setdiff(cur_tunables, new_tunables)

if !isempty(setdiff(new_tunables, cur_tunables))
throw(ArgumentError("""New tunable parameters must be a subset of the current tunable parameters. Found tunable parameters not in the system: $(setdiff(new_tunables, cur_tunables)).
Note that array parameters can only be set as tunable or non-tunable, not partially tunable. They should be specified in the un-scalarized form.
"""))
end
cur_ps = get_ps(sys)
const_ps = toconstant.(diff_params)

for (idx, p) in enumerate(cur_ps)
for (d, c) in zip(diff_params, const_ps)
if isequal(p, d)
setindex!(cur_ps, c, idx)
break
end
end
end
@set! sys.ps = cur_ps
complete(sys)
end
27 changes: 27 additions & 0 deletions test/parameter_dependencies.jl
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,33 @@ end
@test SciMLBase.successful_retcode(sol)
end

@testset "Change Tunables" begin
@variables θ(t)=π/6 ω(t)=0.
@parameters g=9.81 L=1.0 b=0.1 errp=1
eqs = [
D(θ) ~ ω,
D(ω) ~ -(g/L)*sin(θ) - b*ω
]
@named pendulum_sys = System(eqs, t, [θ, ω], [g, L, b])
sys = mtkcompile(pendulum_sys)

new_tunables = [L, b]
sys2 = ModelingToolkit.subset_tunables(sys, new_tunables)
sys2_tunables = ModelingToolkit.tunable_parameters(sys2, ModelingToolkit.parameters(sys2))
@test length(sys2_tunables) == 2
@test isempty(setdiff(sys2_tunables, new_tunables))
@test_throws ArgumentError ModelingToolkit.subset_tunables(sys, [errp])
@test_throws ArgumentError ModelingToolkit.subset_tunables(sys, [θ, L])
sys3 = ModelingToolkit.subset_tunables(sys, [])
sys3_tunables = ModelingToolkit.tunable_parameters(sys3, ModelingToolkit.parameters(sys3))
@test length(sys3_tunables) == 0

sys_incomplete = pendulum_sys
@test_throws ArgumentError ModelingToolkit.subset_tunables(sys_incomplete, new_tunables)
sys_nonsplit = mtkcompile(pendulum_sys; split = false)
@test_throws ArgumentError ModelingToolkit.subset_tunables(sys_nonsplit, new_tunables)
end

struct CallableFoo
p::Any
end
Expand Down
Loading