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

Renewable + PEM Parameterized Bidder #1407

Merged
merged 38 commits into from
Aug 12, 2024
Merged

Conversation

Xinhe-Chen
Copy link
Contributor

Fixes

Add the renewable+PEM parameterized bidder (bids the power at a constant price).

Summary/Motivation:

  1. Add a PerfectForecaster to predict the day-ahead and real-time wind power and electricity prices (if needed).
  2. Add a PEMParameterizedd bidder to bid the renewable power at a constant prices.

Changes proposed in this PR:

Legal Acknowledgement

By contributing to this software project, I agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the license terms described in the LICENSE.txt file at the top level of this directory.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

Copy link
Member

@andrewlee94 andrewlee94 left a comment

Choose a reason for hiding this comment

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

A number of requests regarding improvements to testing.

pyo_unittest.assertStructuredAlmostEqual(
first=result_forecast.tolist(), second=expected_forecast
)
return
Copy link
Member

Choose a reason for hiding this comment

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

Tests should not return anything - this causes a lot of warnings to be emitted in the test output which makes it hard to find real issues. There are 4 more instances of this below as well.

@pytest.mark.unit
@pytest.mark.parametrize("value", [np.array([1,2,3,4,5]), [1,2,3,4,5]])
def test_create_perfectforecaster_with_ndarray_and_list(value):
with pytest.raises(ValueError):
Copy link
Member

Choose a reason for hiding this comment

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

When checking for errors, you should also include the expected text message to ensure you got the right error (and not another of the same type).

return PerfectForecaster(wind_df)

@pytest.mark.unit
def test_create_perfectforecaster(wind_df):
Copy link
Member

Choose a reason for hiding this comment

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

These are more like component tests than unit tests. Unit tests should generally be focused on individual methods/functions in the code to make sure all the elements work correctly in isolation, followed by a few test cases like these to make sure the end-to-end workflow is correct.

Copy link
Contributor

Choose a reason for hiding this comment

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

@Xinhe-Chen, I think you already did this. Is so, just reply here with a short sentence confirming/summarizing what you did.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have addressed this.

TestingForecaster,
testing_model_data,
)
from pyomo.common import unittest as pyo_unittest
Copy link
Member

Choose a reason for hiding this comment

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

Group imports together, starting with native Python packages, then third-party packages, then Pyomo and finally IDAES.


day_ahead_horizon = 24
real_time_horizon = 4
solver = pyo.SolverFactory("cbc")
Copy link
Member

Choose a reason for hiding this comment

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

You should probably add a check to ensure cbc is available in the test environment and to skip these tests if it is not.

return bidder_object


# @pytest.mark.unit
Copy link
Member

Choose a reason for hiding this comment

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

Commented code.

Also, there is not a lot of testing for this class here - there are a number of methods that should be unit tested.

@andrewlee94
Copy link
Member

Also, we will need documentation for the new classes and how to use them.

@Xinhe-Chen
Copy link
Contributor Author

Also, we will need documentation for the new classes and how to use them.

Thank you for your comments! I am still working on improving the tests. The documentation will be added in this PR #1090.

@ksbeattie ksbeattie added the Priority:Normal Normal Priority Issue or PR label May 9, 2024
@Xinhe-Chen
Copy link
Contributor Author

@radhakrishnatg Hi Radhakrishna, would you please review this PR? Thank you!

@Xinhe-Chen
Copy link
Contributor Author

@adowling2 this is ready for review.

@adowling2 adowling2 marked this pull request as ready for review May 28, 2024 17:53
@Xinhe-Chen
Copy link
Contributor Author

@adowling2 This is ready for review.

@Xinhe-Chen
Copy link
Contributor Author

@ksbeattie Hi Keith, we hope to have this PR reviewed and merged next week.

Copy link
Contributor

@adowling2 adowling2 left a comment

Choose a reason for hiding this comment

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

Please see the comments below. These are all asking for minor changes, often just more descriptive comments.

@@ -13,6 +13,155 @@ uncertain price scenario has a corresponding power output. As shown in the figur
each of these uncertain price and power output pairs formulates a segment in the
bidding curves.

Here we present a stochastic bidding model for a renewable integrated energy system (Wind generator + PEM).
Copy link
Contributor

Choose a reason for hiding this comment

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

wind should be lowercase, make sure you define PEM on first use

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 is addressed.

in order to avoid underbidding. Equation (2) states that the RT offering power is the same as the
IES power output to the grid. In the bidding mode, the market rules require the offering power is
non-decreasing (convex) with its marginal cost in an energy bid. This rule is represented by equation (3).
Equation (4) to equation (9) are process model constraints. Equation (10) calculates the operation costs for IES
Copy link
Contributor

Choose a reason for hiding this comment

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

Equations (4) to (9)

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.

This function records the bids and the details in the underlying bidding model.

Arguments:
bids: the obtained bids for this date.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the specific data structure for a bid? Is this a list? Please provide a little more information in the comments

Copy link
Member

Choose a reason for hiding this comment

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

Type hinting would be a good idea. E.g. the method signature could be:

def record_bids(self, bids: list, model, date, hour, market):

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added variable types in code comments.


model: bidding model

date: the date we bid into
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a string or something else?

Copy link
Member

Choose a reason for hiding this comment

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

Typing hinting will help again. Also, remove the line breaks between each argument (otherwise the docs formatter might get confused).

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


date: the date we bid into

hour: the hour we bid into
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this an integer or something else?

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

):
"""
Arguments:
renewable_mw: maximum renewable energy system capacity
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a float? If so, add (float) or , float to the end of the doc string.

Arguments:
renewable_mw: maximum renewable energy system capacity

pem_marginal_cost: the cost/MW above which all available wind energy will be sold to grid;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a float?

pem_marginal_cost: the cost/MW above which all available wind energy will be sold to grid;
below which, make hydrogen and sell remainder of wind to grid

pem_mw: maximum PEM capacity limits how much energy is bid at the `pem_marginal_cost`
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this a float?

- {bus}-DALMP
- {bus}-RTLMP
- {bus}-DACF and {bus}-RTCF for renewable plants
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps add a sentence explaining the perfect forecast has no error and "sees into the future".

Copy link
Contributor

Choose a reason for hiding this comment

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

@Xinhe-Chen, did you do this? If so, please reply here.

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

(expected_DA_cf[t] * pmax, pem_marginal_cost),
]
expect_cost_curve = convert_marginal_costs_to_actual_costs(expect_bids_curve)
expected_bids[t] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this comment addressed? If so, reply here.

@adowling2 adowling2 self-requested a review July 1, 2024 17:11
Copy link
Contributor

@adowling2 adowling2 left a comment

Choose a reason for hiding this comment

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

@Xinhe-Chen, please reply to the open comments to confirm these were addressed.

None

"""
df_list = []
Copy link
Contributor

Choose a reason for hiding this comment

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

@Xinhe-Chen, did you address this comment? If so, please reply here.

- {bus}-DALMP
- {bus}-RTLMP
- {bus}-DACF and {bus}-RTCF for renewable plants
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

@Xinhe-Chen, did you do this? If so, please reply here.

(expected_DA_cf[t] * pmax, pem_marginal_cost),
]
expect_cost_curve = convert_marginal_costs_to_actual_costs(expect_bids_curve)
expected_bids[t] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

@Xinhe-Chen Please reply here if you addressed this.

return PerfectForecaster(wind_df)

@pytest.mark.unit
def test_create_perfectforecaster(wind_df):
Copy link
Contributor

Choose a reason for hiding this comment

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

@Xinhe-Chen, I think you already did this. Is so, just reply here with a short sentence confirming/summarizing what you did.

@Xinhe-Chen
Copy link
Contributor Author

@Xinhe-Chen, please reply to the open comments to confirm these were addressed.

Hi Prof. Dowling, I addressed all comments from you last Friday.

I am going to to a final check later today to ensure no other issues are remaining later today.

@adowling2
Copy link
Contributor

Excellent. Tag me here when it is ready to review.

@Xinhe-Chen
Copy link
Contributor Author

Excellent. Tag me here when it is ready to review.

@adowling2 This is ready for review.

Copy link
Contributor

@adowling2 adowling2 left a comment

Choose a reason for hiding this comment

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

Ready to merge.

Copy link
Member

@andrewlee94 andrewlee94 left a comment

Choose a reason for hiding this comment

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

@Xinhe-Chen I have one final request before we merge this; someone should be added to the top level CODEOWNERS file as the maintainer for this code (i.e. the person Keith or Ludovico will contact if tests start failing). We require all code in apps to have an assigned owner for maintenance purposes.

None
"""

print("")
Copy link
Member

Choose a reason for hiding this comment

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

Using a logger is generally preferred to doing print statements as this gives the end-user more flexibility in how (and what) things are displayed.

Also, for a new line use print("\n"}.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I saw @adowling2 is on the CODEOWNERS roster for the grid_integration codes. I am a PhD student and will graduate in 2 years but I am happy to be responsible for maintaining these codes until I graduate.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Using a logger is generally preferred to doing print statements as this gives the end-user more flexibility in how (and what) things are displayed.

Also, for a new line use print("\n"}.

Done.

Copy link
Member

Choose a reason for hiding this comment

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

I see that you changed the new line, but what about using a logger?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not very familiar with the logger, so I need to look into that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi Andrew, I used logger to replace print and it works. Thank you for letting me know this.

@Xinhe-Chen
Copy link
Contributor Author

@andrewlee94 Hi Andrew, I think I have already addressed your comments. Shall we get this PR merged?

Copy link
Member

@andrewlee94 andrewlee94 left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, I was at a conference or out on leave the past three weeks. A couple of minor requests for changes to how you are using the logger.

idaes/apps/grid_integration/bidder.py Outdated Show resolved Hide resolved
idaes/apps/grid_integration/bidder.py Outdated Show resolved Hide resolved
@Xinhe-Chen
Copy link
Contributor Author

Sorry for the delay, I was at a conference or out on leave the past three weeks. A couple of minor requests for changes to how you are using the logger.

Thank you! I have addressed your new comments.

@ksbeattie ksbeattie enabled auto-merge (squash) August 8, 2024 18:30
@lbianchi-lbl lbianchi-lbl merged commit 04fa887 into IDAES:main Aug 12, 2024
43 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
DISPATCHES Priority:Normal Normal Priority Issue or PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants