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

Add active attribute to components #1038

Merged
merged 9 commits into from
Sep 20, 2024
Merged

Add active attribute to components #1038

merged 9 commits into from
Sep 20, 2024

Conversation

FabianHofmann
Copy link
Collaborator

This PR introduces a new component active which, as discussed, allow to enable/disable assets from pypsa core functionalities. These are

  • optimization
  • power flow
  • statistics

When set to inactive, the optimization masks the corresponding asset out. The asset then still appears in the index but does not contain any value. To save memory (in particular for the myopic optimization), we might change this to a harder filter such that inactive assets do not even appear in the variable blocks in the first place. My preference would be to tackle that after #848.

The PR further introduces as Component class. Note that this is purely non-breaking and non-intrusive. We had a Component object before, which was a namedtuple. With the new class we gain more control when iterating over components. It might as well pave the way to a more formal Component behaviour as discussed on #936.

(Do not merge yet, I would like to see some more tests on the optimization and power flow.)

Checklist

  • Code changes are sufficiently documented; i.e. new functions contain docstrings and further explanations may be given in doc.
  • Unit tests for new features were added (if applicable).
  • Newly introduced dependencies are added to environment.yaml, environment_docs.yaml and setup.py (if applicable).
  • A note for the release notes doc/release_notes.rst of the upcoming release is included.
  • I consent to the release of this PR's code under the MIT license.

problem.lp Outdated
Copy link
Member

Choose a reason for hiding this comment

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

Ups :)

list_name: str
attrs: pd.DataFrame
df: pd.DataFrame
pnl: Dict | dict
Copy link
Member

Choose a reason for hiding this comment

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

Can we drop dict?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

sure

Copy link
Member

@lkstrp lkstrp left a comment

Choose a reason for hiding this comment

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

Looks good to me. But one bigger concern:
We are mixing n.active, n.active_in_investment_period and n.get_active_assets and neither the naming is clear nor is it apparent what the difference is. I would merge them all into one n.active_assets and handle if build year/lifetime should be taken into account in there.
Even cleaner would be to write the build year and lifetime into the active column. Then nothing would get mixed up. But that is probably not reasonable within the current structure, which makes a clean API important.

Otherwise, thanks for the great cleanup. I am not a big fan of the dataclass though. It starts to implement something without changing all the underlying structural issues and nested initialization. But I guess that's okay since it doesn't touch the API.

pypsa/components.py Outdated Show resolved Hide resolved
pypsa/components.py Outdated Show resolved Hide resolved
@property
def network(self) -> Network:
return self._network() # type: ignore
def active_in_investment_period(
Copy link
Member

Choose a reason for hiding this comment

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

Maybe merge that as an optional argument into active_assets?

Also active_asserts_in_investment_period instead, but I think a combined method is cleaner

pypsa/descriptors.py Outdated Show resolved Hide resolved
def get_active_assets(n: Network, c: str, investment_period: ArrayLike) -> pd.Series:
def get_active_assets(
n: Network | SubNetwork, c: str, investment_period: ArrayLike | None = None
) -> pd.Series:
"""
Getter function.

Copy link
Member

Choose a reason for hiding this comment

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

Needs update, specially since we mix active and the build_year/ life_time now and not write back to one

pypsa/statistics.py Show resolved Hide resolved
@FabianHofmann
Copy link
Collaborator Author

thanks for the comments @lkstrp! As for the active assets function, what is needed quite regularly is the index of active assets. With the current get_active_assets that would be

c.df.index[c.get_active_assets()]

which I shortcut to

c.active_assets

but I agree this is confusing. I will revert that and only define get_active_assets() for the Component class. At some point, we should think about a better naming. As I see, the name get_active_assets suggest that you get a listlike object with all active assets, but instead you get a boolean series indicating whether it is active or not. With that proposal, I wanted to introduce a better naming, but let's go step by step.

@FabianHofmann
Copy link
Collaborator Author

For more background: The general issue here is that the activity of an asset has two sources of information

a) the global (new) attribute active which defines activity for all pypsa functionality. This should be independent of any build_year or investment year and enable to fully control whether an assets is there or not.

b) the investment year dependent activity which adds on top and is only considered when doing and multi investment optimization. This is dependent on build_year (input), life_time (input) and investment_year (function argument).

When thinking about different approaches, my feeling is that the rule that static active columns should remain an input only thus not be touched/altered by the code.

@FabianHofmann
Copy link
Collaborator Author

and about the comment about the dataclass, I am happy to remove the dataclass decorator if this is what you meant

@lkstrp
Copy link
Member

lkstrp commented Sep 19, 2024

and about the comment about the dataclass, I am happy to remove the dataclass decorator if this is what you meant

Na, keep it is a it is. It is also so much cleaner than before

Comment on lines 178 to 179
if investment_period is None:
return self.df.active
Copy link
Member

Choose a reason for hiding this comment

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

This check can be ignored now

@lkstrp
Copy link
Member

lkstrp commented Sep 20, 2024

As discussed:

  • Completely moves active_asset logic to Component class
  • Removes Component reference to Network
  • Moves it to own module (definitions). That's how we named it in pypsa-eur. Not sure if it's the best name. But a composition is needed, otherwise we get circular import errors.

@FabianHofmann
Copy link
Collaborator Author

looks great, thanks lukas!

@FabianHofmann FabianHofmann merged commit 42ceb78 into master Sep 20, 2024
21 checks passed
@lkstrp lkstrp mentioned this pull request Sep 25, 2024
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants