Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

defaults returns internal stuff #3408

Open
TorkelE opened this issue Feb 22, 2025 · 15 comments
Open

defaults returns internal stuff #3408

TorkelE opened this issue Feb 22, 2025 · 15 comments
Labels
bug Something isn't working

Comments

@TorkelE
Copy link
Member

TorkelE commented Feb 22, 2025

After the latest update, defaults is broken:

using ModelingToolkit
using ModelingToolkit: t_nounits as t
@parameters p d
@variables X(t)
@mtkbuild osys = ODESystem([Differential(t)(X) ~ p - d*X], t)
defaults(osys) #  Initial(X(t)) => 0
@TorkelE TorkelE added the bug Something isn't working label Feb 22, 2025
@ChrisRackauckas
Copy link
Member

What is internal here?

@TorkelE
Copy link
Member Author

TorkelE commented Feb 26, 2025

Sorry, you mean what is the internal fields od osys?

@TorkelE
Copy link
Member Author

TorkelE commented Feb 26, 2025

If you mean the defaults field, then that is

julia> ModelingToolkit.get_defaults(osys)
Dict{Any, Any} with 1 entry:
  Initial(X(t)) => 0

I.e. default returns the full content of the defaults field, and not just the actual defaults of the model.

@AayushSabharwal
Copy link
Member

Initial is public API. It's not internal.

@AayushSabharwal
Copy link
Member

@TorkelE
Copy link
Member Author

TorkelE commented Feb 27, 2025

I am not really sure, but werenät the Initial things stuff that was added just as a way to make the new initialisation code work, and they are not really a property of the model? I.e. when it was first introduced it wouldn't really change anything and it is e.g. filtered away when parameters are called. Shouldn't it be filtered away for the same reasons in defaults?

And if not, shouldn't it have been marked, or at least mentioned, as a breaking change?

@AayushSabharwal
Copy link
Member

I am not really sure, but werenät the Initial things stuff that was added just as a way to make the new initialisation code work, and they are not really a property of the model?

They are very much a part of the model.

I.e. when it was first introduced it wouldn't really change anything and it is e.g. filtered away when parameters are called.

This was done because parameters returns the parameters added by the user to the model. The user didn't add Initial parameters. Not filtering would break code.

Shouldn't it be filtered away for the same reasons in defaults?
And if not, shouldn't it have been marked, or at least mentioned, as a breaking change?

Why? We never maintain that defaults has the same number of elements as the user-provided defaults. In fact, for the longest time structural_simplify would scalarize array defaults. In fact, if we do the filtering we break a contract that mutating defaults(sys) for a completed system updates defaults.

@TorkelE
Copy link
Member Author

TorkelE commented Feb 27, 2025

This was done because parameters returns the parameters added by the user to the model. The user didn't add Initial parameters. Not filtering would break code

Sorry, it just seemed non-intuitive to me that parameters returns parameters added by the user and defaults adds defaults added by the user and by MTK. In the docs it says:

- parameters(sys): All parameters of the system and its subsystems.
- defaults(sys): A Dict that maps variables/parameters into their default values for the system and its subsystems.

and there is not really anything suggestion that these act in a fundamentally different way.

Even with defaults not changing, it is a breaking change though, no? I.e. I had one piece of code previously where defaults returned something, that exact same piece of code now has it returning another couple of things. I agree we do not need a breaking MTK change for every little breaking change that is made. But surely this is breaking no?

@ChrisRackauckas
Copy link
Member

Let's take a step back. What are you trying to do where giving you all of the parameters is not the right thing to do? Let's find a use case and come up with a solution.

@ChrisRackauckas
Copy link
Member

And let's just stop the argument about "breaking" here. You obviously understand that it's an ill-defined question and not being asked in good faith. It's documented as giving "all parameters", "all defaults". The definition is just not precise enough for this case, we all understand that. You could argue there was a bug before because the initial conditions have always implicitly been parameters of the system (they are mathematically equivalent to parameters) and so omitting them was a bug. You could argue that it's breaking because they weren't there before. The fact of the matter is, Initial(x) is a parameter, and so it's a case that fell through the cracks of the previous definitions. We all understand this, and we can at least all agree that the previous definitions in the docs were not sufficiently precise enough to say whether or not this information should be included or not.

So, if we are going to move forward, let's discuss:

  1. what interfaces we need
  2. why we need them
  3. How to more precisely define their guarantees.

@TorkelE
Copy link
Member Author

TorkelE commented Feb 27, 2025

When creating a model, users are able to define and add various stuffs to them. That includes e.g. events, observables, and default values. I think it would be useful for a user to be able to extract these defaults from a system (e.g. those not related to initialization).

@ChrisRackauckas
Copy link
Member

What are you trying to extract and why would you want to have the subset that does not include the initialization variables/parameters?

@TorkelE
Copy link
Member Author

TorkelE commented Feb 28, 2025

My personal application was a case in which I had various models. In each there are some (intermediary) species which I know start at 0.0, so I had given them default values 0.0. Then I am looping across various initial condition and running simulations. In this case I had a routine which checked the defaults and filtered out the species in that, which gave me the species with the non-trivial initial conditions. For now I have solved this with replacing the old defaults with a defaults_new which filters out and defaults involving the Initial function.

@ChrisRackauckas
Copy link
Member

Can you share some code? I'm having trouble parsing what you're doing there.

@TorkelE
Copy link
Member Author

TorkelE commented Mar 1, 2025

I have a code base where I run simulations for different models.
When declaring each model, I set some initial conditions to 0.
When running the simulations, to generate initial conditions, I retrieve the defaults, as that is one easy way to figure out for which species I need to generate initial conditions (i.e. those not in defaults).

I have changed my code now. If you guy wants/don't want to reimplement the old defaults function that is fine. I just raised this because I thought I found a bug (as mentioned, from the docs it is not very clear they treat initial conditions differently), and then pointed out that there might be code depending on the defaults function's previous behaviour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants