make branch filters and interfaces compatible - #267
Conversation
|
Performance Results
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
luke-kiernan
left a comment
There was a problem hiding this comment.
I'm finding the logic here hard to follow: it seems like a tripping hazard for users and future devs. At the very least, I'd suggest making this "widening" opt-in instead of on-by-default.
Another thought: could you get the same results merely by re-writing your filter function? I haven't dug into the details of services, but basically
new_filter(x) = old_filter(x) || x in [something]| service_name::String, | ||
| ) | ||
| PSY.get_available(branch) || return | ||
| entry = get!(ServiceBranchRequirement, forced, typeof(branch)) |
There was a problem hiding this comment.
typeof(branch) -> type parameter
| network_formulation <: AreaPTDFNetworkModel && return forced | ||
| services_mapping = PSY.get_contributing_device_mapping(sys) | ||
| isempty(services_mapping) && return forced | ||
| for service_model in values(service_models) |
There was a problem hiding this comment.
Some type instability here: values(service_models) looks like it's heterogeneous, typeof(service). Might be worth asking AI how much can be done about that
| The branches that must be modeled because a service model in the template depends on their | ||
| flow, keyed by concrete branch type. Read from the system's own contributing-device mapping | ||
| rather than from the service model's map, which has already been narrowed by component type | ||
| and so cannot report a branch type the template fails to model. |
There was a problem hiding this comment.
Read from the system's own contributing-device mapping
rather than from the service model's map, which has already been narrowed by component type
and so cannot report a branch type the template fails to model.
Well that's rather confusing
| requirement. This is what keeps a rebuild from leaving a stale widening in place after the | ||
| template or system data changes between `build!` passes (a service model removed from the | ||
| template, or every interface branch made unavailable) — the old early-return-on-empty and | ||
| continue-on-no-entry left the previous pass's `WidenedBranchFilter` installed in both cases. |
There was a problem hiding this comment.
Do we have test cases for these?
| @@ -108,6 +259,8 @@ function validate_template_impl!(model::IOM.AbstractOptimizationModel) | |||
| for k in branch_keys_to_delete | |||
| delete!(template.branches, k) | |||
There was a problem hiding this comment.
pre-existing perf nitpick: make branch_keys_to_delete a set and then do set difference
You could get the same behavior from a filter function, but this makes it harder for the user to write a simple filter function. This PR is just encoding the assumption that if I am modeling an interface that includes branches, those branches must be modeled. Note that we still error if the user has decided not to model a type at all that is in an interface. In that case, the user needs to make a deliberate change (to add the device or remove the interface). |
@jd-lara Do you have a preference of if we widen the branch filter automatically to include branches that appear in services, or error and require the user to include those branches by modifying the user provided filter function? If we do just rely on the filter function, we still need to make the change to error (right now the answer is silently wrong) |
We only have a service the transmission interface, we should catch the user setting a filter and the interface and do the right thing otherwise it can be a mess with 100s of GTCs |
|
@jarry7 any thoughts on this in effect always including the lines in the interfaces regardless of the filter. We either need to fail loudly that the filter is inconsistent with the interfaces or just handle it under the hood. |
|
Articulating my concerns more precisely: I don't like how the filters change mid-process. Innoncent refactoring--e.g. caching the items that pass a filter--suddenly now can cause major changes in behavior. Going forward, if I have a function that uses filters, I need to think: where does it belong relative to the "widening" step? imo that's bad, a recipe for headaches and bugs. Alternatives: maintain a collection of "extra things we also need to model" somewhere? edit: assigning the modified filter to a different kwarg (add, don't overwrite) would address my objections on paper...but having 2 things that are almost but not quite the same is also bad. Then you need to keep track of which to use where. |
The true solution for this is to implement something like this So we can compose filtering adequately instead than with an arbitrary function |
|
Due to my work in PNM, it occurred to me to ask: how do I asked Claude about this: not exactly a bug, but certianly confusing.
|
I think the answer here is to pin branches in the interface from being reduced. This is already the policy for DLRs, controllable transformers, etc. It is the same idea, if the template needs to include something to model it correctlyh, it should be pinned from reductions. This is orthogonal to the filtering question. My suggestion is this:
Open issue and Implement later:
|
|
Also relevant to this discussion is handling monitored components of a contingency. This can fail currently if a monitored component is filtered about by the user provided filter. |
Fixes #266