-
Notifications
You must be signed in to change notification settings - Fork 27
Ard integration for wind farm combined performance and cost model #312
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: develop
Are you sure you want to change the base?
Changes from all commits
5d1fd35
bb38a07
7a50791
cf6f99c
70b9cbc
7e807b9
3383d99
c499c7f
1af4bdf
1402a47
95b311c
92744e7
284291c
a0834cf
69fb21c
9c0c415
e31e296
4f01420
4bf6bb2
9bf8ff2
2f3dd3e
80cf490
6def61c
3be97e1
f8f0ae7
f503605
b7d4934
0a122f1
9f1fb67
67d1842
0254d0a
bc5dfac
cb27a1d
fd6247c
46696b7
f1d5b7d
ae42667
c42c48a
ea68c23
572b99e
3382e0e
5c299f8
9b6ce3b
7dd8472
8ef1120
d88502a
bd41ad9
80fed27
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,34 @@ | ||
| # Wind Plant - Ard | ||
|
|
||
| The intent of [Ard](https://github.com/WISDEM/Ard) is to be a modular, full-stack multi-disciplinary optimization tool for wind farms. By incorporating Ard in H2Integrate, we are able to draw on many wind technology models developed at NREL and other institutions without managing them or their connections in Ard. Models connected in Ard include many parts of [WISDEM](https://github.com/WISDEM/WISDEM), [FLORIS](https://github.com/NREL/floris), and [OptiWindNet](https://github.com/DTUWindEnergy/OptiWindNet). Ard also provides constraint functions and wind farm layout generation capabilities among other things. Because Ard has been developed in a modular way, you may extend Ard fairly easily to include other wind models of interest. | ||
|
|
||
| Ard is included in H2Integrate as an [OpenMDAO sub-model](https://openmdao.org/newdocs/versions/latest/features/building_blocks/components/submodel_comp.html), which means that Ard is treated as a distinct and separate OpenMDAO system within the larger H2I OpenMDAO system. In this way, the user can run an independent wind farm optimization within Ard, or allow H2Integrate to manage the wind farm design variables directly. The drawback of including Ard as a sub-model is that N2 diagrams made from the H2Integrate problems will show Ard only as a single black-box model, rather than showing all the subsystems within Ard. If you wish to view an N2 diagram of Ard, you will need to use the Ard problem instead. | ||
|
|
||
| ## Some Key Capabilities of Ard | ||
| - Highly modular to include alternate/new models and capabilities | ||
| - Built using OpenMDAO | ||
| - Wind farm layout optimization | ||
| - Turbine locations | ||
| - Ordered grid layouts | ||
| - Continuous locations layouts | ||
| - Boundaries | ||
| - Single boundary | ||
| - Multiple discrete boundary regions | ||
| - Arbitrary polygonal boundaries shapes | ||
| - Collection cable array optimization | ||
| - OptiWindNet | ||
| - Radial configurations | ||
| - Branched configurations | ||
| - Aerodynamics | ||
| - FLORIS | ||
| - Cost and finance | ||
| - WISDEM | ||
| - LandBOSSE | ||
| - ORBIT | ||
| - FinanceSE | ||
|
|
||
| ## Wind Resource | ||
|
Collaborator
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. Could you specify what wind resource data is needed by ard and what the units should be? like that and needs wind speeds in m/s or whatever? Cause if folks are downloading resource data from the openmeteo web API - they may have wind speed in km/h (that's the default unit) |
||
| The wind resource capabilities of H2Integrate are not yet connected with Ard, so the user must provide a wind resource file directly to the Ard model inputs. | ||
|
Collaborator
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 because of how the wind resource needs to be formatted? If yes, could you explain the necessary format of the file and what the attributes--or column--requirements are)?
Collaborator
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. it looks like you're using openmeteo, is this something that you're integrating @elenya-grant?
Collaborator
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. yes - PR #332
Collaborator
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. I have not connected Ard to the wind resource capabilities in H2I because it would require passing weather data at run time, but Ard requires the weather data at setup time. |
||
|
|
||
| ## Examples | ||
| For an example of using Ard in an H2Integrate model, see `examples/xx_wind_ard`. Note that Ard uses a combination of input files, including a [wind IO](https://github.com/IEAWindSystems/windIO) file. | ||
|
Collaborator
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. Could you add a list of the necessary input files for ARD, with maybe a one sentence description about them?
Collaborator
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. Agreed, and pointing to the Ard docs where possible here would be quite helpful!
Collaborator
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. If this example is really similar to |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| name: h2integrate | ||
| name: h2i-ard | ||
| channels: | ||
| - conda-forge | ||
| - defaults | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1142,6 +1142,78 @@ def test_simple_dispatch_example(subtests): | |
| assert pytest.approx(electricity_lcoe, rel=1e-6) == 78.01723 | ||
|
|
||
|
|
||
| def test_windard_pv_battery_dispatch_example(subtests): | ||
| # Change the current working directory to the example's directory | ||
| os.chdir(EXAMPLE_DIR / "xx_wind_ard") | ||
|
|
||
| # Create the model | ||
| model = H2IntegrateModel("./h2i_inputs/wind_pv_battery.yaml") | ||
|
|
||
| # Run the model | ||
| model.run() | ||
|
|
||
| # Post-process the results | ||
| model.post_process() | ||
|
|
||
| with subtests.test("Check wind generation"): | ||
|
Collaborator
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 there a reason to not set the generation to a value? It seems like it might be easier to check in the future if this test breaks if we have a better idea of the value.
Collaborator
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. I agree with Kaitlin - I think that having subtests on the value of the total wind generation profile and total solar generation profile would be a good so if other subtests fail (like LCOE or total electricity dispatched, etc), it will be easier to identify what causes other subtest failures. |
||
| # Wind should generate some electricity | ||
| wind_electricity = model.prob.get_val("wind.electricity_out", units="MW") | ||
| assert wind_electricity.sum() > 0 | ||
|
|
||
| with subtests.test("Check solar generation"): | ||
| # Solar should generate some electricity | ||
| solar_electricity = model.prob.get_val("solar.electricity_out", units="MW") | ||
| assert solar_electricity.sum() > 0 | ||
|
|
||
| with subtests.test("Check battery gets wind and solar output"): | ||
| # Wind plus solar electricity should match battery input (direct connection) | ||
| battery_electricity_in = model.prob.get_val("battery.electricity_in", units="MW") | ||
| assert wind_electricity.sum() + solar_electricity.sum() == pytest.approx( | ||
| battery_electricity_in.sum(), rel=1e-6 | ||
| ) | ||
|
|
||
| with subtests.test("Check demand satisfaction"): | ||
| dispatched_electricity = model.prob.get_val("battery.electricity_out", units="MW") | ||
| # Demand should be met for the last part of the year | ||
| assert np.allclose( | ||
| dispatched_electricity[8700:], | ||
| model.prob.get_val("battery.electricity_demand", units="MW")[8700:], | ||
| ) | ||
|
|
||
| # Subtest for LCOE | ||
| with subtests.test("Check dispatched LCOE value"): | ||
| lcoe = model.prob.get_val("finance_subgroup_dispatched_electricity.LCOE")[0] | ||
| assert pytest.approx(lcoe, rel=1e-6) == 0.22171693744337054 | ||
|
|
||
| with subtests.test("Check generation LCOE value (excludes battery)"): | ||
| lcoe = model.prob.get_val("finance_subgroup_produced_electricity.LCOE")[0] | ||
| assert pytest.approx(lcoe, rel=1e-6) == 0.06770722531229562 | ||
|
|
||
| # Subtest for total electricity produced | ||
| with subtests.test("Check total electricity dispatched"): | ||
| total_electricity = model.prob.get_val( | ||
| "finance_subgroup_dispatched_electricity.electricity_sum.total_electricity_produced", | ||
| units="MW*h/year", | ||
| ).sum() | ||
| assert total_electricity == pytest.approx(dispatched_electricity.sum()) | ||
|
|
||
| # Subtest for electricity curtailed | ||
| with subtests.test("Check electricity curtailed"): | ||
| electricity_curtailed = model.prob.get_val( | ||
| "battery.electricity_unused_commodity", units="MW" | ||
| ).sum() | ||
|
|
||
| # import pdb; pdb.set_trace() | ||
| assert electricity_curtailed == pytest.approx(525088.2729268058, rel=1e-6) | ||
|
|
||
| # Subtest for missed load | ||
| with subtests.test("Check electricity missed load"): | ||
| electricity_missed_load = np.linalg.norm( | ||
| model.prob.get_val("battery.electricity_unmet_demand", units="MW") | ||
| ) | ||
| assert electricity_missed_load == pytest.approx(468.28057304873026) | ||
|
|
||
|
|
||
| def test_csvgen_design_of_experiments(subtests): | ||
| os.chdir(EXAMPLE_DIR / "20_solar_electrolyzer_doe") | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| Wind Speed [m/s],Power [kW],Cp [-],Thrust [kN],Ct [-] | ||
| 3,40.52,0.208546508,77.66,1.132034888 | ||
| 4,177.67,0.385795061,121.90,0.999470963 | ||
| 5,403.9,0.449038264,174.88,0.917697381 | ||
| 6,737.59,0.474546985,236.23,0.860849503 | ||
| 7,1187.18,0.480994449,304.55,0.815371198 | ||
| 7.1,1239.25,0.481172749,311.87,0.811614904 | ||
| 7.2,1292.52,0.481235678,319.27,0.807939328 | ||
| 7.3,1347.32,0.481305875,326.77,0.80443352 | ||
| 7.4,1403.26,0.481238912,334.35,0.800993851 | ||
| 7.5,1460.7,0.481167356,342.03,0.79768116 | ||
| 7.6,1519.64,0.481081935,349.82,0.794529244 | ||
| 7.7,1580.17,0.481007003,357.72,0.791495834 | ||
| 7.8,1642.11,0.480880409,365.71,0.788560434 | ||
| 7.9,1705.76,0.480789285,374.51,0.787217182 | ||
| 8,1771.17,0.480737341,384.00,0.787127977 | ||
| 9,2518.55,0.480111543,485.21,0.785839257 | ||
| 10,3448.38,0.479218839,597.48,0.783812219 | ||
| 10.1,3552.14,0.479120347,609.30,0.783568108 | ||
| 10.2,3657.95,0.479022984,621.23,0.783328285 | ||
| 10.3,3765.12,0.478834971,631.75,0.781194418 | ||
| 10.4,3873.93,0.478597234,640.86,0.777292539 | ||
| 10.5,3984.48,0.478324162,650.02,0.773464375 | ||
| 10.6,4096.58,0.477994289,659.23,0.769690236 | ||
| 10.7,4210.72,0.477665338,668.51,0.766001924 | ||
| 10.8,4326.15,0.477253698,677.81,0.762348072 | ||
| 10.9,4443.4,0.476819542,687.17,0.758760824 | ||
| 11,4562.5,0.476368667,696.60,0.755242872 | ||
| 11.1,4683.42,0.475896732,706.08,0.751792927 | ||
| 11.2,4806.16,0.475404347,715.65,0.748434131 | ||
| 11.3,4929.93,0.474814698,725.25,0.745113997 | ||
| 11.4,5000.92,0.469087611,711.09,0.717806682 | ||
| 11.5,5000.16,0.456886723,677.65,0.672204789 | ||
| 11.6,4999.98,0.445156758,654.72,0.63831272 | ||
| 11.7,4999.96,0.433837552,636.70,0.610176496 | ||
| 11.8,4999.98,0.422902868,621.40,0.585456847 | ||
| 11.9,5000,0.412332387,607.97,0.563222111 | ||
| 12,5000,0.402110045,595.94,0.542912273 | ||
| 13,5000.01,0.316270768,514.41,0.399312061 | ||
| 14,5000.01,0.253224057,463.93,0.310517829 | ||
| 15,5000.02,0.205881042,426.43,0.248633226 | ||
| 16,5000,0.169640239,397.20,0.203543725 | ||
| 17,5000.02,0.141430529,373.66,0.169616419 | ||
| 18,5000.03,0.119144335,354.36,0.143478955 | ||
| 19,5000.02,0.101304591,338.30,0.122938861 | ||
| 20,5000.04,0.086856409,324.77,0.106515296 | ||
| 21,5000.02,0.075029591,312.72,0.093026095 | ||
| 22,5000.05,0.065256635,301.23,0.081648606 | ||
| 23,5000.01,0.057109143,291.13,0.072197368 | ||
| 24,5000,0.050263779,282.71,0.064388275 | ||
| 25,5000.04,0.044470536,275.29,0.057782745 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| name: Test case | ||
| wind_resource: | ||
| time: | ||
| - '2023-01-01T00:00:00Z' | ||
| - '2023-01-01T01:00:00Z' | ||
| - '2023-01-01T02:00:00Z' | ||
| - '2023-01-01T03:00:00Z' | ||
| - '2023-01-01T04:00:00Z' | ||
| - '2023-01-01T05:00:00Z' | ||
| - '2023-01-01T06:00:00Z' | ||
| - '2023-01-01T07:00:00Z' | ||
| - '2023-01-01T08:00:00Z' | ||
| - '2023-01-01T09:00:00Z' | ||
| turbulence_intensity: | ||
| data: | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| - 0.1 | ||
| wind_direction: | ||
| - 54 | ||
| - 42 | ||
| - 71 | ||
| - 67 | ||
| - 66 | ||
| - 65 | ||
| - 69 | ||
| - 76 | ||
| - 84 | ||
| - 100 | ||
| wind_speed: | ||
| - 1.36 | ||
| - 4.46 | ||
| - 7.18 | ||
| - 7.08 | ||
| - 6.67 | ||
| - 6.94 | ||
| - 6.96 | ||
| - 6.5 | ||
| - 6.13 | ||
| - 5.18 |
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.
Would it be possible to show how a user would create an Ard problem instead of just the H2Integrate problem?