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

[Feature] Link inverter and rectifier capacity #155

Open
remmyd opened this issue Jun 21, 2021 · 19 comments
Open

[Feature] Link inverter and rectifier capacity #155

remmyd opened this issue Jun 21, 2021 · 19 comments
Assignees
Labels
enhancement New feature or request

Comments

@remmyd
Copy link
Collaborator

remmyd commented Jun 21, 2021

Currently the rectifier and inverter capacity are optimized individually eventhough they should represent a bi-directional inverter. Linking them together could enhance offgridders. What would be a good way to start on this issue?

@smartie2076 smartie2076 self-assigned this Jun 22, 2021
@smartie2076 smartie2076 added the enhancement New feature or request label Jun 22, 2021
@smartie2076
Copy link
Collaborator

Hello @remmyd! Glad to hear from you. I agree that this is not an ideal representation (and related to #31).

I have already noted down some hints in the MVS issues (rl-institut/multi-vector-simulator#24 (comment)) already:

I might have found an inbuild-functionality to connect two inverter assets: https://oemof-solph.readthedocs.io/en/latest/usage.html#adding-additional-constraints

Coupling of two variables e.g. investment variables) with a factor -> equate_variables()

Also see here and here (Code).

So, I think you did not work with oemof yet, right? This will be a jump into cold water for you. This is how I would go about it:

  • Read the documentation of equate_variables()
  • Try and simulate the example code from above including the constraint, as well as an oemof-model without that constraint. I am not sure if you want to do that, as that would mean that requires you dive into oemof a bit (but in a managable way). Look at the lp-file of your code snippet and check how the constraint looks there.
  • Create an abstract frunction that calls the equate_variables() in G2b_constraints_custom.py
  • Figure out whether a bi-directional inverter is always the goal if inverter and rectifyier are activated, or if there are reasons to explicitly want two uni-directional transformers. Think about how / where you want future users to enable/disable the bi-directional asset constraint.
  • Add function call to the G2b function after
    # ------------Rectifier AC DC------------#
    to , or place it in a loop within those lines
  • Add function call to the G2b function after
    # ------------ main grid bus and subsequent sources if necessary------------#
    to , or place it in a loop within those lines
  • Think of a pytest for the user input turning off/on the bi-directionality constraint
  • Think of a pytest making sure that the bi-directionality constraint works as intended

... as you see, this is already a pretty large issue. You can learn basically everything you need to program a tool like Offgridders, but it requires a lot from you. Depending on your learning style, you might want to adress a smaller issue first, to get to know the github flow first.

@smartie2076
Copy link
Collaborator

smartie2076 commented Jun 29, 2021

I have heard you are not sure how to share code with me. There are actually different options:

  1. Directly share the code-snippet in CODE markdown format in the post (three apostrophes around the code, see "Insert Code <ctrl +e>"). This will make it easily quotable.
  2. If your code is too long for that, and you do not expect much feedback anyway, share it as an attachment to one of your posts (not sure if it can be a .py file, if not, change the format by renaming it to a .txt file)
  3. If you need extensive feedback on your code, eg. as your have bugs in your code, AND you are planning to make a PR later on anyway, you can also already open a PR. Att the file in the root of the repository/project. Then you commit that file separately from any other changes and push. The goal then is to create a working code together, and then move snippets into the real src code folder and remove the working file later on. Make sure you create a draft PR, not a real PR!

@remmyd
Copy link
Collaborator Author

remmyd commented Jun 29, 2021

Hi @smartie2076, thanks for the reply. I used parts of test_connect_invest.py from the code example you shared above. I'll attach it to this post. The equal_variables() function does set the two transformers to the same capacity ('invest' variable for transformer 2 is set equal to transformer 1 invest variable eventhough transformer 2 is not used). If the function is commented out the transformer 2 variable is set to 0. Thus, it seem to do what we want. The constraint in the lp-file looks like the following:

c_e_equate_InvestmentFlow_invest(powerline_1_2_electricity2)_InvestmentFlow_invest(powerline_2_1_electricity1)_: +1 InvestmentFlow_invest(powerline_1_2_electricity2) -1 InvestmentFlow_invest(powerline_2_1_electricity1) = 0

test_oemof_equate_variables_constraint.txt

@remmyd remmyd closed this as completed Jun 29, 2021
@remmyd remmyd reopened this Jun 29, 2021
@smartie2076
Copy link
Collaborator

This is looking good then! I think we would implement

# define aliases for shorter calls below
line12 = energysystem.groups['powerline_1_2']
line21 = energysystem.groups['powerline_2_1']

# equate investment flows.
solph.constraints.equate_variables(om,om.InvestmentFlow.invest[line12, bel2], om.InvestmentFlow.invest[line21, bel1])

A bit differently - I think I called the investmentFlows differently in Offgridders:

CAP_inverter += model.InvestmentFlow.invest[el_bus, inverter]

(This is just one example for a call for an inverter).

probably, your function would look more like this:

def constraint_equate_bi-directional_transformer_capacities(model, case_dict, el_bus, dc_bus, transformer_in, transformer_out, name_transformer_in, name_transformer_out):
        CAP_inverter = 0 
        CAP_rectifyer = 0
        if case_dict[name_transformer_in] != None and case_dict[name_transformer_out] != None:
            if case_dict[name_transformer_in] is False and case_dict[name_transformer_out] is False:
                  CAP_inverter += model.InvestmentFlow.invest[el_bus, inverter]
                  CAP_rectifyer += model.InvestmentFlow.invest[dc_bus, rectifyer]
       solph.constraints.equate_variables(model,CAP_inverter, CAP_recitfyer)

Notes:

  • I am using a generalized function with name_transformer_in and transformer_in etc. here because then you can apply the function to both the PCC and the bi-directional inverter by just calling it twice).
  • I think it is called the dc_bus for the rectifyer, but I am not sure. It is the bus connected to the PV panel/battery.

@smartie2076
Copy link
Collaborator

Ah, and of couse you need an if-loop somehow that would make sure that you only apply the constraint when appropriate.

@smartie2076
Copy link
Collaborator

Do you have an answer to the following question yet?

  • Figure out whether a bi-directional inverter is always the goal if inverter and rectifyier are activated, or if there are reasons to explicitly want two uni-directional transformers. Think about how / where you want future users to enable/disable the bi-directional asset constraint.

@remmyd
Copy link
Collaborator Author

remmyd commented Jun 29, 2021

Thanks for the hints. I think letting the user decide if they want to link the inverter and the rectifier together is a good idea. I also saw in this publication that the inverter and rectifier can be linked by a capacity ratio factor, and if I am not mistaken Homer also defines the rectifier as a % of the inverter. However, I am unsure on how we would implement this.

For the if-loop you mentioned would you call it outside of the function then in G1?

@smartie2076
Copy link
Collaborator

smartie2076 commented Jun 29, 2021

Yeah, Homer also does that: https://www.homerenergy.com/products/pro/docs/3.10/converter.html

Basically, you would also add a parameter like inverter_rectifyer_capactiy_ratio_factor, and then the user can define if they assume it to be 1 or <1. Then, use

CAP_inverter_with_capacity_ratio = CAP_inverter * inverter_rectifyer_capactiy_ratio_factor
solph.constraints.equate_variables(model,CAP_inverter_with_capacity_ratio , CAP_recitfyer)

This results in 0=CAP_rectifyer-CAP_inverter*inverter_rectifyer_capactiy_ratio_factor or CAP_rectifyer=inverter_rectifyer_capactiy_ratio_factor*CAP_inverter

@smartie2076
Copy link
Collaborator

I did call the if-loops for the other constraints in G1, see:

# ------------Renewable share constraint------------#

You can follow that approach for now.

In the end, we will still have to figure out how to easiest add pytests for the new constraints, and then you might need to move the if-loop (but that is no big thing!).

@smartie2076
Copy link
Collaborator

CAP_inverter_with_capacity_ratio = CAP_inverter * inverter_rectifyer_capactiy_ratio_factor
solph.constraints.equate_variables(model,CAP_inverter_with_capacity_ratio , CAP_recitfyer)

This results in 0=CAP_rectifyer-CAP_inverter*inverter_rectifyer_capactiy_ratio_factor or CAP_rectifyer=inverter_rectifyer_capactiy_ratio_factor*CAP_inverter

I ment in the LP-file, you could also try that out with your code snippet! That would even be the best approach, actually :)

@remmyd
Copy link
Collaborator Author

remmyd commented Jun 29, 2021

Yes, that makes, sense. equal_variables() actually has the option to use a factor:

equate_variables(model, CAP_rectifier , CAP_inverter, inverter_rectifier_capactiy_ratio_factor)

which result in the same constraint: CAP_rectifier==inverter_rectifier_capactiy_ratio_factor*CAP_inverter (tested with the code snippet)

I guess this would be useful if the user gives only an inverter cost. The options now would be:

  1. let the user give inverter costs and use a inverter_rectifier_capactiy_ratio_factor
  2. let the user give bidirectional costs and set inverter and rectifier capacity to the same value
  3. let the user give inverter and rectifier costs and treat them as two uni-directional transformers

I am usure if they all make sense or if we should decide on which one to use.

@smartie2076
Copy link
Collaborator

smartie2076 commented Jul 5, 2021

Hi @remmyd! Sorry about the delay.

I think you can cover all of them with following data:

  • inverter_rectifier_capactiy_ratio_factor
  • use_bidirectional_inverter_constraint
  • inverter_costs
  • rectifier_costs

for 1), you could print a warning if the costs for both rectifyer costs and inverter costs are added (Are you sure that you want to define both rectifyer and inverter costs if you link the capacties to receive a biderectional inverter? This would ressult in effective costs of X currency/kW bidirectional inverter.) By default, the costs would basically be added. Also makes sense if you want to compare 2 scenarios with one PV+diesel and one PV+storage+diesel.

for 2), Same as above, just that inverter_rectifier_capactiy_ratio_factor=1

for 3) Same as above, use_bidirectional_inverter_constraint would make sure that we have unidirectional transformers.

...so, I think you only need to add inverter_rectifier_capactiy_ratio_factor and use_bidirectional_inverter_constraint in the appropiate section of the xlsx input file. Maybe send a proposal as to where you think they would be best suited? I am guessint inverter_rectifier_capactiy_ratio_factor on tab costants and use_bidirectional_inverter_constraint either on simulation_settings or on cases.

@remmyd
Copy link
Collaborator Author

remmyd commented Jul 8, 2021

Hi @smartie2076 !

Makes sense, I would suggest add inverter_rectifier_capactiy_ratio_factor indeed to constant and use_bidirectional_inverter_constraint to cases to give the user more flexibility. Two questions:

  1. Where in the code would I add the reading and addition to case_dict of these two values?
  2. When you talk about the inverter and rectifier costs do you mean their inverstment costs or total costs?
    `

@smartie2076
Copy link
Collaborator

Makes sense, I would suggest add inverter_rectifier_capactiy_ratio_factor indeed to constant and use_bidirectional_inverter_constraint to cases to give the user more flexibility. Two questions:

1. Where in the code would I add the reading and addition to case_dict of these two values?

I think the inverter_rectifier_capactiy_ratio_factor will be automatically parsed when you add it to tab constant:

def get_parameters_constant(file, sheet_input_constant):

Same goes for use_bidirectional_inverter_constraint in cases:

def get_case_definitions(file, sheet_project_sites):

Mainly, you need to make sure that the simulation also works if the user does not provide these two parameters as well. You should implement that as two benchmark tests (or more). This makes sure that old users can still use their old input files to use Offgridders.

2. When you talk about the inverter and rectifier costs do you mean their inverstment costs or total costs?

I am taking about the development costs, the specific costs and the specific operation and management costs. They should/should not be linked/added according to the setting. I think the dispatch costs may be different.

@remmyd
Copy link
Collaborator Author

remmyd commented Jul 13, 2021

Alright. Do you already have an idea where I should check if the two parameters are provided or not? Are there other parameters where this was already implemented?
I saw that in the following function the case dict is updated for every case, I guess I could add lines there that test if use_bidirectional_inverter_constraint is an instance and if not give it as default value False?

def update_dict(capacities_oem, specific_case, experiment):

@smartie2076
Copy link
Collaborator

I think you can check if inverter_rectifier_capactiy_ratio_factor is provided with this function, which should raise a logging.warning if the parameter is not provided and your default value is used.

def test_techno_economical_parameters_complete(experiment):

For use_bidirectional_inverter in tab case_definitions, you would add a check in B.get_case_definitions(), like here:

if case_definitions[case][EVALUATION_PERSPECTIVE] not in [

You should, though, raise a logging.warning and automatically set the parameter to False to make sure you do not create API changes (API changes require a major release, as current users of Offgridders can not use their input files anymore).

@smartie2076
Copy link
Collaborator

Remember: You can already push the slightest bits of code you already created into a PR.

@remmyd
Copy link
Collaborator Author

remmyd commented Jul 14, 2021

Hi @smartie2076,

I have a first draft ready to push but I think I don't have access to the github. When I use the command git push origin feature/link_inverter_rectifier. I get the the message Permission to rl-institut/offgridders.git denied to remmyd.

@smartie2076
Copy link
Collaborator

Sorry about that, I now created write-access for you. Does it work now?

I have to let you know that I am on vacation starting tomorrow afternoon, so I will not be able to review your pull request in the next two weeks...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants