03: Simplified Floating#
In this example, we run Ard on a simplified floating platform problem.
We follow Example 02 closely, so descriptions are more sparse.
from pathlib import Path # optional, for nice path specifications
import pprint as pp # optional, for nice printing
import numpy as np # numerics library
import matplotlib.pyplot as plt # plotting capabilities
import windIO
import ard # technically we only really need this
from ard.utils.io import load_yaml # we grab a yaml loader here
from ard.api import set_up_ard_model # the secret sauce
from ard.viz.layout import plot_layout # a plotting tool!
import openmdao.api as om # for N2 diagrams from the OpenMDAO backend
# import optiwindnet.plotting
%matplotlib inline
# load input
path_inputs = Path.cwd().absolute() / "inputs"
input_dict = load_yaml(path_inputs / "ard_system.yaml")
# set up system
prob = set_up_ard_model(input_dict=input_dict, root_data_path=path_inputs)
Running OpenMDAO util to clean the output directories...
No OpenMDAO output directories found.
... done.
Created top-level OpenMDAO problem: top_level.
Adding top_level.
Adding layout2aep.
Adding layout to layout2aep.
Adding aepFLORIS to layout2aep.
Activating approximate totals on layout2aep
Adding landuse.
Adding collection.
Adding mooring_design.
Adding mooring_constraint.
Adding spacing_constraint.
Adding tcc.
Adding orbit.
Adding opex.
Adding financese.
System top_level built.
System top_level set up.
Some new components are added to the Ard model here, comparing to Example 02:
mooring_design: designs the mooring system, here simply by doing straight-line mooring lines to the constant-valued seafloormooring_constraint: a module to compute a constraint function to make sure the moorings don't violate regulatory requirements on proximity
# visualize model
if False:
om.n2(prob)
# run the model
prob.run_model()
# collapse the test result data
test_data = {
"AEP_val": float(prob.get_val("AEP_farm", units="GW*h")[0]),
"CapEx_val": float(prob.get_val("tcc.tcc", units="MUSD")[0]),
"BOS_val": float(prob.get_val("orbit.total_capex", units="MUSD")[0]),
"OpEx_val": float(prob.get_val("opex.opex", units="MUSD/yr")[0]),
"LCOE_val": float(prob.get_val("financese.lcoe", units="USD/MW/h")[0]),
"area_tight": float(prob.get_val("landuse.area_tight", units="km**2")[0]),
"coll_length": float(prob.get_val("collection.total_length_cables", units="km")[0]),
"mooring_spacing": float(
np.min(prob.get_val("mooring_constraint.mooring_spacing", units="km"))
),
"turbine_spacing": float(
np.min(prob.get_val("spacing_constraint.turbine_spacing", units="km"))
),
}
print("\n\nRESULTS:\n")
pp.pprint(test_data)
print("\n\n")
UserWarning: /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/floris/core/flow_field.py:169
'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None.
ORBIT library intialized at '/opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/library'
RESULTS:
{'AEP_val': 410.14878567258273,
'BOS_val': 994.1921261768098,
'CapEx_val': 118.75948972475001,
'LCOE_val': 226.31146168189625,
'OpEx_val': 9.350000000000001,
'area_tight': 13.2496,
'coll_length': 21.89865877023397,
'mooring_spacing': 0.042875983926893214,
'turbine_spacing': 0.91}
optimize = True # set to False to skip optimization
if optimize:
# run the optimization
prob.run_driver()
prob.cleanup()
prob.check_totals(compact_print=True, show_only_incorrect=True)
# collapse the test result data
test_data = {
"spacing_primary": float(prob.get_val("spacing_primary")[0]),
"spacing_secondary": float(prob.get_val("spacing_secondary")[0]),
"angle_orientation": float(prob.get_val("angle_orientation")[0]),
"angle_skew": float(prob.get_val("angle_skew")[0]),
"AEP_val": float(prob.get_val("AEP_farm", units="GW*h")[0]),
"CapEx_val": float(prob.get_val("tcc.tcc", units="MUSD")[0]),
"BOS_val": float(prob.get_val("orbit.total_capex", units="MUSD")[0]),
"OpEx_val": float(prob.get_val("opex.opex", units="MUSD/yr")[0]),
"LCOE_val": float(prob.get_val("financese.lcoe", units="USD/MW/h")[0]),
"area_tight": float(prob.get_val("landuse.area_tight", units="km**2")[0]),
"coll_length": float(
prob.get_val("collection.total_length_cables", units="km")[0]
),
"mooring_spacing": float(
np.min(prob.get_val("mooring_constraint.mooring_spacing", units="km"))
),
"turbine_spacing": float(
np.min(prob.get_val("spacing_constraint.turbine_spacing", units="km"))
),
}
# clean up the recorder
prob.cleanup()
# print the results
print("\n\nRESULTS (opt):\n")
pp.pprint(test_data)
print("\n\n")
# plot convergence
## read cases
cr = om.CaseReader(
prob.get_outputs_dir() / input_dict["analysis_options"]["recorder"]["filepath"]
)
# Extract the driver cases
cases = cr.get_cases("driver")
# Initialize lists to store iteration data
iterations = []
objective_values = []
# Loop through the cases and extract iteration number and objective value
for i, case in enumerate(cases):
iterations.append(i)
obj_keys = input_dict["analysis_options"]["objectives"].keys()
assert (len(obj_keys)) == 1
objective_values.append(
case.get_objectives()[next(iter(obj_keys))] # get the unique entry
)
# Plot the convergence
plt.figure(figsize=(8, 6))
plt.plot(iterations, objective_values, marker="o", label="Objective (LCOE)")
plt.xlabel("Iteration")
plt.ylabel("Objective Value (Total Cable Length (m))")
plt.title("Convergence Plot")
plt.legend()
plt.grid()
plt.show()
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|0
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([0.]),
'angle_skew': array([0.]),
'spacing_primary': array([7.]),
'spacing_secondary': array([7.])}
UserWarning: /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/floris/core/flow_field.py:169
'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None.
Objectives
{'collection.total_length_cables': array([21898.65877023])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|1
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([0.]),
'angle_skew': array([0.]),
'spacing_primary': array([7.]),
'spacing_secondary': array([7.])}
UserWarning: /opt/hostedtoolcache/Python/3.11.15/x64/lib/python3.11/site-packages/floris/core/flow_field.py:169
'where' used without 'out', expect unitialized memory in output. If this is intentional, use out=None.
Objectives
{'collection.total_length_cables': array([21898.65877023])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|2
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.00169981]),
'angle_skew': array([-0.00247939]),
'spacing_primary': array([6.97727015]),
'spacing_secondary': array([6.98376224])}
Objectives
{'collection.total_length_cables': array([21836.22659655])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|3
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.01182038]),
'angle_skew': array([-0.00488319]),
'spacing_primary': array([6.86364301]),
'spacing_secondary': array([6.90258908])}
Objectives
{'collection.total_length_cables': array([21524.14814719])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|4
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.0354046]),
'angle_skew': array([-0.14220988]),
'spacing_primary': array([6.55392293]),
'spacing_secondary': array([6.67001219])}
Objectives
{'collection.total_length_cables': array([20658.61893805])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|5
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.03527828]),
'angle_skew': array([-0.14589906]),
'spacing_primary': array([6.55384971]),
'spacing_secondary': array([6.64457632])}
Objectives
{'collection.total_length_cables': array([20625.4411911])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|6
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02091876]),
'angle_skew': array([-0.16122459]),
'spacing_primary': array([6.55386143]),
'spacing_secondary': array([6.55383148])}
Objectives
{'collection.total_length_cables': array([20507.59301867])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|7
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02126326]),
'angle_skew': array([-0.16133396]),
'spacing_primary': array([6.55384647]),
'spacing_secondary': array([6.55382035])}
Objectives
{'collection.total_length_cables': array([20507.5506663])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|8
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02808669]),
'angle_skew': array([-0.16292084]),
'spacing_primary': array([6.55385166]),
'spacing_secondary': array([6.55382316])}
Objectives
{'collection.total_length_cables': array([20507.55075989])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|9
--------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02453102]),
'angle_skew': array([-0.16209392]),
'spacing_primary': array([6.55384896]),
'spacing_secondary': array([6.55382169])}
Objectives
{'collection.total_length_cables': array([20507.55071005])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|10
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02282978]),
'angle_skew': array([-0.16169828]),
'spacing_primary': array([6.55384766]),
'spacing_secondary': array([6.55382099])}
Objectives
{'collection.total_length_cables': array([20507.55068703])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|11
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02201459]),
'angle_skew': array([-0.16150869]),
'spacing_primary': array([6.55384704]),
'spacing_secondary': array([6.55382066])}
Objectives
{'collection.total_length_cables': array([20507.55067619])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|12
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02162369]),
'angle_skew': array([-0.16141779]),
'spacing_primary': array([6.55384674]),
'spacing_secondary': array([6.5538205])}
Objectives
{'collection.total_length_cables': array([20507.55067103])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|13
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02143619]),
'angle_skew': array([-0.16137418]),
'spacing_primary': array([6.5538466]),
'spacing_secondary': array([6.55382042])}
Objectives
{'collection.total_length_cables': array([20507.55066857])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|14
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02134623]),
'angle_skew': array([-0.16135326]),
'spacing_primary': array([6.55384653]),
'spacing_secondary': array([6.55382038])}
Objectives
{'collection.total_length_cables': array([20507.55066739])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|15
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02130307]),
'angle_skew': array([-0.16134322]),
'spacing_primary': array([6.5538465]),
'spacing_secondary': array([6.55382036])}
Objectives
{'collection.total_length_cables': array([20507.55066682])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|16
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02128236]),
'angle_skew': array([-0.1613384]),
'spacing_primary': array([6.55384649]),
'spacing_secondary': array([6.55382036])}
Objectives
{'collection.total_length_cables': array([20507.55066655])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|17
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02127243]),
'angle_skew': array([-0.16133609]),
'spacing_primary': array([6.55384648]),
'spacing_secondary': array([6.55382035])}
Objectives
{'collection.total_length_cables': array([20507.55066642])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|18
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-0.02126766]),
'angle_skew': array([-0.16133498]),
'spacing_primary': array([6.55384647]),
'spacing_secondary': array([6.55382035])}
Objectives
{'collection.total_length_cables': array([20507.55066636])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|19
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-1.06737782]),
'angle_skew': array([-0.39506431]),
'spacing_primary': array([6.55430466]),
'spacing_secondary': array([6.5538596])}
Objectives
{'collection.total_length_cables': array([20506.5507933])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|20
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-2.37852401]),
'angle_skew': array([-0.68803555]),
'spacing_primary': array([6.5549008]),
'spacing_secondary': array([6.55412396])}
Objectives
{'collection.total_length_cables': array([20505.88566688])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|21
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-29.60593667]),
'angle_skew': array([-6.77139009]),
'spacing_primary': array([6.56118421]),
'spacing_secondary': array([6.5616759])}
Objectives
{'collection.total_length_cables': array([20555.06390447])}
Driver debug print for iter coord: rank0:ScipyOptimize_SLSQP|22
---------------------------------------------------------------
Design Vars
{'angle_orientation': array([-5.63851371]),
'angle_skew': array([-1.41640712]),
'spacing_primary': array([6.55565312]),
'spacing_secondary': array([6.55502817])}
Objectives
{'collection.total_length_cables': array([20504.53666797])}
Iteration limit reached (Exit mode 9)
Current function value: 1.0252268333985624
Iterations: 10
Function evaluations: 22
Gradient evaluations: 11
Optimization FAILED.
Iteration limit reached
-----------------------------------
-----------------
Total Derivatives
-----------------
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| 'of' variable | 'wrt' variable | calc val @ max viol | fd val @ max viol | (calc-fd) - (a + r*fd) | error desc |
+====================================+===================+=====================+===================+========================+===================+
| AEP_farm | angle_orientation | -2.496802e+17 | -3.143930e+11 | 2.496799e+17 | 2.496799e+17>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| AEP_farm | angle_skew | 1.610595e+17 | -2.042171e+11 | 1.610597e+17 | 1.610597e+17>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| AEP_farm | spacing_primary | 1.855168e+09 | -2.321905e+11 | 2.340455e+11 | 2.340455e+11>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| AEP_farm | spacing_secondary | 5.405708e+09 | 2.908631e+11 | 2.854571e+11 | 2.854571e+11>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| collection.total_length_cables | angle_orientation | 9.063113e-01 | 1.338211e+00 | 4.318984e-01 | 4.318984e-01>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| collection.total_length_cables | angle_skew | -1.911863e+00 | -1.941769e+00 | 2.990369e-02 | 2.990369e-02>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| spacing_constraint.turbine_spacing | angle_orientation | -2.285185e-04 | 0.000000e+00 | 2.285185e-04 | 2.285185e-04>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| spacing_constraint.turbine_spacing | angle_skew | 1.865928e-04 | 0.000000e+00 | 1.865928e-04 | 1.865928e-04>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| spacing_constraint.turbine_spacing | spacing_primary | -8.951173e-16 | 4.656613e-10 | 4.656617e-10 | 4.656617e-10>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
| spacing_constraint.turbine_spacing | spacing_secondary | 1.376855e-14 | -4.656613e-10 | 4.656746e-10 | 4.656746e-10>TOL |
+------------------------------------+-------------------+---------------------+-------------------+------------------------+-------------------+
RESULTS (opt):
{'AEP_val': 440.5479229177636,
'BOS_val': 993.5788953738085,
'CapEx_val': 118.75948972475001,
'LCOE_val': 210.59088933602834,
'OpEx_val': 9.350000000000001,
'angle_orientation': -5.638513705269998,
'angle_skew': -1.4164071157514626,
'area_tight': 11.619761537753096,
'coll_length': 20.504536667971248,
'mooring_spacing': 0.0635583900012834,
'spacing_primary': 6.55565312253702,
'spacing_secondary': 6.5550281704696225,
'turbine_spacing': 0.8522349059298125}
plot_layout(prob, input_dict=input_dict, show_image=True, include_cable_routing=True)
<Axes: >