-
Notifications
You must be signed in to change notification settings - Fork 3
Implement complex CHP template #3
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
base: main
Are you sure you want to change the base?
Changes from all commits
3ef4be1
985ba53
83b8e5d
380a865
80b1af7
1718243
abfb720
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,221 @@ | ||||||||||||||||||||||||||||||
| parameters: | ||||||||||||||||||||||||||||||
| mode: ~ # operation mode: extraction, condensing, backpressure | ||||||||||||||||||||||||||||||
| fuel: ~ # fuel carrier | ||||||||||||||||||||||||||||||
| fuel_from: ~ # fuel input node | ||||||||||||||||||||||||||||||
| power_to: ~ # electricity output node | ||||||||||||||||||||||||||||||
| heat_to: ~ # condensing only if not given | ||||||||||||||||||||||||||||||
| co2_to: ~ # no CO2 tracking if not given | ||||||||||||||||||||||||||||||
| fuel_co2_emission_factor: ~ # CO2 emission factor of the fuel | ||||||||||||||||||||||||||||||
| power_max: ~ # maximum electricity output | ||||||||||||||||||||||||||||||
| heat_max: ~ # maximum heat output | ||||||||||||||||||||||||||||||
| power_at_heat_max: ~ # electricity output at maximum heat output | ||||||||||||||||||||||||||||||
| power_ratio: 0.55 # electricity per heat in backpressure operation | ||||||||||||||||||||||||||||||
| power_loss_ratio: 0.20 # electricity lost per heat extracted along an isofuel line | ||||||||||||||||||||||||||||||
| efficiency_condensing: ~ # electricity per fuel | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
| efficiency_backpressure: ~ # electricity+heat per fuel | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this now the combined efficiency? maybe use that term?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
| # TODO: | ||||||||||||||||||||||||||||||
| # power_min: 0 | ||||||||||||||||||||||||||||||
| # heat_min: 0 | ||||||||||||||||||||||||||||||
| # efficiency_condensing_min: ~ | ||||||||||||||||||||||||||||||
| # efficiency_backpressure_min: ~ | ||||||||||||||||||||||||||||||
| # availability: ~ | ||||||||||||||||||||||||||||||
| # availability_factor: ~ | ||||||||||||||||||||||||||||||
| # other missing parameters: ramping, specific unit commitment settings, etc. | ||||||||||||||||||||||||||||||
| _turbine_outputs: ~ | ||||||||||||||||||||||||||||||
| _turbine_conversion: ~ | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| components: | ||||||||||||||||||||||||||||||
| turbine: | ||||||||||||||||||||||||||||||
| type: Unit | ||||||||||||||||||||||||||||||
| inputs: {<fuel>: <fuel_from>} | ||||||||||||||||||||||||||||||
| outputs: <_turbine_outputs> | ||||||||||||||||||||||||||||||
| conversion: <_turbine_conversion> | ||||||||||||||||||||||||||||||
| capacity: <power_max> out:electricity | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| heat: | ||||||||||||||||||||||||||||||
| type: Unit | ||||||||||||||||||||||||||||||
| enabled: <mode> == extraction | ||||||||||||||||||||||||||||||
sstroemer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
| inputs: {electricity: <self>.aux_node} | ||||||||||||||||||||||||||||||
| outputs: {heat: <heat_to>} | ||||||||||||||||||||||||||||||
| conversion: 1 electricity -> <power_loss_ratio> heat | ||||||||||||||||||||||||||||||
| capacity: <heat_max> out:heat | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| aux_node: | ||||||||||||||||||||||||||||||
| type: Node | ||||||||||||||||||||||||||||||
| enabled: <mode> == extraction | ||||||||||||||||||||||||||||||
| carrier: electricity | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| power: | ||||||||||||||||||||||||||||||
| type: Connection | ||||||||||||||||||||||||||||||
| enabled: <mode> == extraction | ||||||||||||||||||||||||||||||
| node_from: <self>.aux_node | ||||||||||||||||||||||||||||||
| node_to: <power_to> | ||||||||||||||||||||||||||||||
| lb: 0 | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # TODO: discuss that these functions get really hard to read/maintain when they grow larger (since in a YAML) | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To me, the confusing part is the lack of conversions at the units. Could we reference the lines as a comment or is this stupid?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How much overhead is it to include individual units (e.g., one additional one for backpressure because the modeling via combined efficiency is different anyhow?) Then we could also have the backpressure calculation with the extraction-calculation-method.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We'll do that sounds helpful! |
||||||||||||||||||||||||||||||
| # should we just default to addons? | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| functions: | ||||||||||||||||||||||||||||||
| validate: | | ||||||||||||||||||||||||||||||
| # TODO: A lot of additional validation checks. | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Check mandatory parameters. | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("mode")) | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("fuel")) | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("fuel_from")) | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("power_to")) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Check mode. | ||||||||||||||||||||||||||||||
| @check this.get("mode") in ["extraction", "condensing", "backpressure"] | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Check for non-negativity. | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("power_max")) || (this.get("power_max") >= 0) | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("heat_max")) || (this.get("heat_max") >= 0) | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("power_at_heat_max")) || (this.get("power_at_heat_max") >= 0) | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("power_ratio")) || (this.get("power_ratio") >= 0) | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("power_loss_ratio")) || (this.get("power_loss_ratio") >= 0) | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("efficiency_condensing")) || (this.get("efficiency_condensing") >= 0) | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("efficiency_backpressure")) || (this.get("efficiency_backpressure") >= 0) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Mode dependent checks. | ||||||||||||||||||||||||||||||
| if this.get("mode") == "backpressure" | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("heat_to")) | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("efficiency_backpressure")) | ||||||||||||||||||||||||||||||
| elseif this.get("mode") == "condensing" | ||||||||||||||||||||||||||||||
| @check isnothing(this.get("heat_to")) | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("efficiency_condensing")) | ||||||||||||||||||||||||||||||
| elseif this.get("mode") == "extraction" | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("heat_to")) | ||||||||||||||||||||||||||||||
| @check !isnothing(this.get("efficiency_condensing")) || !isnothing(this.get("efficiency_backpressure")) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| prepare: | | ||||||||||||||||||||||||||||||
| cm = this.get("power_ratio") | ||||||||||||||||||||||||||||||
| cv = this.get("power_loss_ratio") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| fuel = this.get("fuel") | ||||||||||||||||||||||||||||||
| to_p = this.get("power_to") | ||||||||||||||||||||||||||||||
| to_co2 = this.get("co2_to") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if this.get("mode") == "backpressure" | ||||||||||||||||||||||||||||||
| to_h = this.get("heat_to") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| # Prepare: power_max, heat_max, power_ratio | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| p_max = this.get("power_max") | ||||||||||||||||||||||||||||||
| h_max = this.get("heat_max") | ||||||||||||||||||||||||||||||
| cm = this.get("power_ratio") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if isnothing(p_max) | ||||||||||||||||||||||||||||||
| power_max = cm * h_max | ||||||||||||||||||||||||||||||
| this.set("power_max", power_max) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if isnothing(h_max) | ||||||||||||||||||||||||||||||
| # Currently, nothing to do here (`h_max` is not actively used in backpressure mode). | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if isnothing(cm) | ||||||||||||||||||||||||||||||
| cm = p_max / h_max | ||||||||||||||||||||||||||||||
| this.set("power_ratio", cm) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
Comment on lines
+119
to
+122
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Being super picky (or will you prevent the input-combination 'cm+h_max+p_at_h_max' in the validate section):
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After discussion => we do not want want to allow over-specification, therefore we check for that in the validate, and then do not need to care about any over-specified combinations. |
||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| # Prepare: eta_p, eta_h | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| eta = this.get("efficiency_backpressure") | ||||||||||||||||||||||||||||||
| eta_h = eta / (1.0 + cm) | ||||||||||||||||||||||||||||||
| eta_p = cm * eta_h | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| this.set("_turbine_outputs", "{electricity: $(to_p), heat: $(to_h)}") | ||||||||||||||||||||||||||||||
| this.set("_turbine_conversion", "1 $(fuel) -> $(eta_p) electricity + $(eta_h) heat") | ||||||||||||||||||||||||||||||
| elseif this.get("mode") == "condensing" | ||||||||||||||||||||||||||||||
| eta_p = this.get("efficiency_condensing") | ||||||||||||||||||||||||||||||
| this.set("_turbine_outputs", "{electricity: $(to_p)}") | ||||||||||||||||||||||||||||||
| this.set("_turbine_conversion", "1 $(fuel) -> $(eta_p) electricity") | ||||||||||||||||||||||||||||||
| elseif this.get("mode") == "extraction" | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| # Prepare: power_max, heat_max, power_ratio, power_loss_ratio | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| p_max = this.get("power_max") | ||||||||||||||||||||||||||||||
| h_max = this.get("heat_max") | ||||||||||||||||||||||||||||||
| p_at_h_max = this.get("power_at_heat_max") | ||||||||||||||||||||||||||||||
| cm = this.get("power_ratio") | ||||||||||||||||||||||||||||||
| cv = this.get("power_loss_ratio") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if isnothing(p_max) | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confusing to me. Isn´t p_max one of the required inputs. Why wouldn´t you have this one. |
||||||||||||||||||||||||||||||
| p_max = isnothing(p_at_h_max) ? (cm * h_max + cv * h_max) : (p_at_h_max + cv * h_max) | ||||||||||||||||||||||||||||||
sstroemer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
| this.set("power_max", p_max) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if isnothing(h_max) | ||||||||||||||||||||||||||||||
| h_max = isnothing(p_at_h_max) ? (p_max / (cm + cv)) : (p_at_h_max / cm) | ||||||||||||||||||||||||||||||
| this.set("heat_max", h_max) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
| if isnothing(cm) | ||||||||||||||||||||||||||||||
| cm = p_at_h_max / h_max | ||||||||||||||||||||||||||||||
| this.set("power_ratio", cm) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if isnothing(cv) | ||||||||||||||||||||||||||||||
| cv = (p_max - p_at_h_max) / h_max | ||||||||||||||||||||||||||||||
| this.set("power_loss_ratio", cv) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| # Prepare: eta_p | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
| eta_p = nothing | ||||||||||||||||||||||||||||||
| eta_cd = this.get("efficiency_condensing") | ||||||||||||||||||||||||||||||
| eta_bp = this.get("efficiency_backpressure") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if !isnothing(eta_cd) && isnothing(eta_bp) | ||||||||||||||||||||||||||||||
| eta_p = eta_cd | ||||||||||||||||||||||||||||||
| elseif isnothing(eta_cd) && !isnothing(eta_bp) | ||||||||||||||||||||||||||||||
| eta_p = eta_bp / (1.0 + cm) | ||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check. I arrive at:
Suggested change
|
||||||||||||||||||||||||||||||
| elseif !isnothing(eta_cd) && !isnothing(eta_bp) | ||||||||||||||||||||||||||||||
| eta_p = eta_cd | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| @check isapprox(eta_cd, eta_bp / (1.0 + cm)) | ||||||||||||||||||||||||||||||
| if !isapprox(eta_cd, eta_bp / (1.0 + cm)) | ||||||||||||||||||||||||||||||
| @error "Falling back to condensing efficiency, to keep model running, but this error should be fixed!" | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
| # ------------------------------------------------- | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| aux_node = "$(this.get("self")).aux_node" | ||||||||||||||||||||||||||||||
| this.set("_turbine_outputs", "{electricity: $(aux_node)}") | ||||||||||||||||||||||||||||||
| this.set("_turbine_conversion", "1 $(fuel) -> $(eta_p) electricity") | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if !isnothing(to_co2) | ||||||||||||||||||||||||||||||
| t_out = this.get("_turbine_outputs") | ||||||||||||||||||||||||||||||
| t_conv = this.get("_turbine_conversion") | ||||||||||||||||||||||||||||||
| ef = this.get("fuel_co2_emission_factor") | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| this.set("_turbine_outputs", "$(t_out[1:end-1]), co2: $(to_co2)}") | ||||||||||||||||||||||||||||||
| this.set("_turbine_conversion", "$(t_conv) + $(ef) co2") | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| finalize: | | ||||||||||||||||||||||||||||||
| if this.get("mode") == "backpressure" | ||||||||||||||||||||||||||||||
| this.exp.out_electricity = this.turbine.exp.out_electricity | ||||||||||||||||||||||||||||||
| this.exp.out_heat = this.turbine.exp.out_heat | ||||||||||||||||||||||||||||||
| elseif this.get("mode") == "condensing" | ||||||||||||||||||||||||||||||
| this.exp.out_electricity = this.turbine.exp.out_electricity | ||||||||||||||||||||||||||||||
| elseif this.get("mode") == "extraction" | ||||||||||||||||||||||||||||||
| this.exp.out_electricity = this.power.exp.out | ||||||||||||||||||||||||||||||
| this.exp.out_heat = this.heat.exp.out_heat | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # Construct the lower-bound / backpressure constraint. | ||||||||||||||||||||||||||||||
| JuMP.@constraint(this.model, this.exp.out_electricity .>= this.get("power_ratio") .* this.exp.out_heat) | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| if !isnothing(this.get("co2_to")) | ||||||||||||||||||||||||||||||
| this.exp.out_co2 = this.turbine.exp.out_co2 | ||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like that but maybe too crowded then.