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

Fallback components in generated formulas #1037

Conversation

ela-kotulska-frequenz
Copy link
Contributor

@ela-kotulska-frequenz ela-kotulska-frequenz commented Aug 16, 2024

Fallback components are used in generated formulas. If primary components is unavailable, formula will generate metric from fallback components. Fallback formulas are implemented for:

  • PVPowerFormula
  • ProducerPowerFormula
  • BatteryPowerFormula
  • ConsumerPowerFormula
  • GridPowerFormula

All necessary formulas are implemented in this PR

@ela-kotulska-frequenz ela-kotulska-frequenz added part:tests Affects the unit, integration and performance (benchmarks) tests priority:high Address this as soon as possible type:enhancement New feature or enhancement visitble to users part:data-pipeline Affects the data pipeline labels Aug 16, 2024
@ela-kotulska-frequenz ela-kotulska-frequenz self-assigned this Aug 16, 2024
@ela-kotulska-frequenz ela-kotulska-frequenz requested a review from a team as a code owner August 16, 2024 07:00
@ela-kotulska-frequenz ela-kotulska-frequenz requested review from Marenz and removed request for a team August 16, 2024 07:00
@ela-kotulska-frequenz ela-kotulska-frequenz linked an issue Aug 16, 2024 that may be closed by this pull request
@github-actions github-actions bot added the part:docs Affects the documentation label Aug 16, 2024
@ela-kotulska-frequenz ela-kotulska-frequenz changed the title Fallback components Fallback components in formula Aug 16, 2024
@ela-kotulska-frequenz ela-kotulska-frequenz changed the title Fallback components in formula Fallback metric in formula Aug 16, 2024
@ela-kotulska-frequenz ela-kotulska-frequenz force-pushed the fallback_components branch 2 times, most recently from 39526b0 to 54cb9c8 Compare August 16, 2024 09:46
@ela-kotulska-frequenz ela-kotulska-frequenz changed the title Fallback metric in formula Fallback components in generated formulas Aug 20, 2024
Copy link
Contributor

@llucax llucax left a comment

Choose a reason for hiding this comment

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

I just gave this a quick look. Will leave it for people more familiar with the formula engine.

Copy link
Contributor

@shsms shsms left a comment

Choose a reason for hiding this comment

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

The logic looks good to me.

Would be nice if you put the docstrings and comments through a grammar checker like https://languagetool.org/ or https://www.grammarly.com/grammar-check.

Comment on lines 43 to 67
def start(self) -> None:
"""Initialize formula engine and start fetching samples."""
self._formula_engine = self._formula_generator.generate() # type: ignore[assignment]
assert isinstance(self._formula_engine, FormulaEngine)
self._receiver = self._formula_engine.new_receiver()
Copy link
Contributor

Choose a reason for hiding this comment

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

Mmm, interesting, but with this implementation stop() and cancel() will not work. I guess cancel() could still be a NOP, but you should probably override stop().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

stop() should work because it has :

        if not self._tasks:
            return

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, I guess I reviewed this too quickly and didn't realized the missing stop() in the comment was this stop. I also missed that even when it had a run() method it didn't actually have any task running. I think I saw a run() and stop() and immediately assumed it had some task running.

I think this class is actually a good match for the new abstract Service interface, and a good case for splitting the ServiceBase with a basic implementation using tasks, as it doesn't really help in this case but it is nice to still have the common Service interface with start/stop/is_running/etc. for consistency.

Copy link
Contributor Author

@ela-kotulska-frequenz ela-kotulska-frequenz Aug 23, 2024

Choose a reason for hiding this comment

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

Ok, I will do that later today (or on Monday).

Copy link
Contributor Author

@ela-kotulska-frequenz ela-kotulska-frequenz Aug 23, 2024

Choose a reason for hiding this comment

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

frequenz-core-python has no release, yet.
Should I add dependency to the v1.x.x?

Maybe I could do that in separate PR (this one is pretty big now)?

Copy link
Contributor

Choose a reason for hiding this comment

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

No, sorry, I didn't mean to do it now, but I actually got thinking about this, and I wonder why isn't this just a Receiver with a couple of extra methods and we are already using stop() for some receivers (like in Merger.

Part of the reasons of splitting this to core is so we can use core in channels too, and maybe make these Receivers a Service too.

So my suggestion would be to make it a Receiver (so fetch_next() would just be receive()) and follow the interface of Service so in the future when this can inherit from Service it is not a breaking change.

OR, you can leave things are they are and we take care of it when we introduce the dependency to core, which will probably need adapting many other classes :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This can't be Receiver, because stopping Receiver won't stop formula.
Here i would like to start/stop formula when needed. This means: subscribe/unsubscribe from all formula components, too.

Copy link
Contributor

Choose a reason for hiding this comment

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

I still don't get this.

So there is no stop() for now (or there is one inherited from BackgroundService that doesn't do anything).

I guess in the future you want to add a stop(). You are saying this stop() should not stop the self._formula_engine? Or the self._receiver? Or both? In any case, if you make FallbackMetricFetcher a Receiver, why can't you just make stop() do whatever it should do? If it is a semantic issue, maybe you could call it pause() instead of stop() to better convey that it is not entirely stopped but just not producing values anymore temporarily?

I think it was also mentioned before, I find it confusing that we have this extra inheritance FallbackFormulaMetricFetcher -> FallbackMetricFetcher. Can't we get rid of FallbackMetricFetcher? What is it for? We already have some unnecessary inheritance in the SDK from the past, I would prefer not to introduce more unless it is really necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, I made it Receiver.

@ela-kotulska-frequenz ela-kotulska-frequenz force-pushed the fallback_components branch 3 times, most recently from b5bfa34 to db41689 Compare August 23, 2024 15:08
Copy link
Contributor

@shsms shsms left a comment

Choose a reason for hiding this comment

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

Still looking into it, but got a couple of items.

@ela-kotulska-frequenz
Copy link
Contributor Author

first commit: _get_metric_fallback_components method is wrong, fixing it now.

FallbackMericFetcher stores fallback formula but generates
and subscribes for it on demand.

Signed-off-by: Elzbieta Kotulska <[email protected]>
Change PVPowerFormula to get primary and fallback of the given
components. For the fallback comonents sub formulas are created
This makes sure that both main and fallback formulas have the
same behaviour and less complexity.

Signed-off-by: Elzbieta Kotulska <[email protected]>
Signed-off-by: Elzbieta Kotulska <[email protected]>
This receiver is only to forward messages to subscribers.
It doesn't need more then 1 last message.
No tests are broken after this.

Signed-off-by: Elzbieta Kotulska <[email protected]>
Signed-off-by: Elzbieta Kotulska <[email protected]>
Previously if no_meter was True, meter was created but
didn't send values. Now no meter is created.
No tests are failing after this change

Signed-off-by: Elzbieta Kotulska <[email protected]>
And fix graph in test_batter_pool_power_two_batteries_per_inverter,
Previously meters were connected to the grid and had no successors,
inverters were connected to grid and had no meter.
Now meters are connected to the inverters.

Signed-off-by: Elzbieta Kotulska <[email protected]>
Fix mockMicrogrid: create senders always in the same order.
Previous solution was working because we had simple graphs.

Signed-off-by: Elzbieta Kotulska <[email protected]>
This should simplify code

Signed-off-by: Elzbieta Kotulska <[email protected]>
@llucax
Copy link
Contributor

llucax commented Aug 30, 2024

We need it because of circular imports :( We would have: FormulaGenerator -> FormulaEngine -> MetricFetcher -> FallbackFormulaMetricFetcher -> FormulaGenerator

Now we have FormulaGenerator -> FallbackFormulaMetricFetcher -> FallbackMetricFetcher FormulaGenerator -> FormulaEngine -> MetricFetcher -> FallbackMetricFetcher

#1037 (comment)

I added comment to the FallbackFormulaMetricFetcher: 23299b4#diff-9800776f7bac0eccbc7d0779b356f024334b154255b892b353dd85c69201f1bfR15

I see 😢

@shsms
Copy link
Contributor

shsms commented Aug 30, 2024

The switch to Receiver interface for FallbackMetricFetcher has made it much simpler and opens the door for more future cleanup.

I'd like to see two more changes, can be in this PR or can be turned into an issue:

  1. I feel the latest_sample field in FallbackFormulaMetricFetcher doesn't belong there. It took me a while to figure out how it was used in the MetricFetcher.

    Instead, I'd like to see a variable _latest_fallback_sample in the MetricFetcher itself, because that's where it is used. So keeping it entirely there would make it easier to follow when it gets set as well as when it gets read. And the FallbackMetricFetcher.latest_sample field can go away.

  2. Then we can rename the FallbackMetricFetcher abc to LazyReceiver and move it to _internal._channels. And FallbackFormulaMetricFetcher can be renamed to FallbackFormulaMetricReceiver.

NB: if you're doing it in this PR, please put in a new commit, so it is easier to read the changes.

shsms
shsms previously approved these changes Aug 30, 2024
Copy link
Contributor

@shsms shsms left a comment

Choose a reason for hiding this comment

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

This is great, one more really cool SDK feature!

Approving from my side, but please wait for @llucax's approval also.

Because that's where it is used.

Signed-off-by: Elzbieta Kotulska <[email protected]>
@ela-kotulska-frequenz
Copy link
Contributor Author

@sahas-subramanian-frequenz

I feel the latest_sample field in FallbackFormulaMetricFetcher doesn't belong there. It took me a while to figure out how it was used in the MetricFetcher.

Done (last commit)

Then we can rename the FallbackMetricFetcher abc to LazyReceiver and move it to _internal._channels. And FallbackFormulaMetricFetcher can be renamed to FallbackFormulaMetricReceiver.

In separate PR: #1056

@shsms
Copy link
Contributor

shsms commented Aug 30, 2024

@sahas-subramanian-frequenz

I don't use that account anymore, so I won't be notified if you use it.

The latest commit looks good as well.

Copy link
Contributor

@llucax llucax left a comment

Choose a reason for hiding this comment

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

This is great, one more really cool SDK feature!

➕ 1

Thanks for taking care of it!

@ela-kotulska-frequenz ela-kotulska-frequenz added this pull request to the merge queue Aug 30, 2024
Merged via the queue into frequenz-floss:v1.x.x with commit 82dcb63 Aug 30, 2024
18 checks passed
@ela-kotulska-frequenz ela-kotulska-frequenz deleted the fallback_components branch August 30, 2024 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
part:data-pipeline Affects the data pipeline part:docs Affects the documentation part:tests Affects the unit, integration and performance (benchmarks) tests priority:high Address this as soon as possible type:enhancement New feature or enhancement visitble to users
Projects
Development

Successfully merging this pull request may close these issues.

Fallback components in generated formulas in LogicalMeter
4 participants