Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions ard/api/interface.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import importlib
import openmdao.api as om
from openmdao.drivers.doe_driver import DOEGenerator
from ard.utils.io import load_yaml, replace_key_value
from ard.cost.wisdem_wrap import (
LandBOSSE_setup_latents,
Expand Down Expand Up @@ -111,6 +112,7 @@ def set_up_ard_model(input_dict: Union[str, dict], root_data_path: str = None):
def set_up_system_recursive(
input_dict: dict,
system_name: str = "top_level",
work_dir: str = "ard_prob_out",
parent_group=None,
modeling_options: dict = None,
analysis_options: dict = None,
Expand All @@ -129,7 +131,7 @@ def set_up_system_recursive(
"""
# Initialize the top-level problem if no parent group is provided
if parent_group is None:
prob = om.Problem()
prob = om.Problem(work_dir=work_dir)
parent_group = prob.model
# parent_group.name = "ard_model"
else:
Expand Down Expand Up @@ -199,7 +201,30 @@ def set_up_system_recursive(
# set up driver
if "driver" in analysis_options:
Driver = getattr(om, analysis_options["driver"]["name"])
prob.driver = Driver()

# handle DOE drivers with special treatment
if Driver == om.DOEDriver:
generator = None
if "generator" in analysis_options["driver"]:
if type(analysis_options["driver"]["generator"]) == dict:
gen_dict = analysis_options["driver"]["generator"]
generator = getattr(om, gen_dict["name"])(
**gen_dict["args"]
)
elif isinstance(
analysis_options["driver"]["generator"], DOEGenerator
):
generator = analysis_options["driver"]["generator"]
else:
raise NotImplementedError(
"Only dictionary-specified or OpenMDAO "
"DOEGenerator generators have been implemented."
)
prob.driver = Driver(generator)
else:
prob.driver = Driver()

# handle the options now
if "options" in analysis_options["driver"]:
for option, value_driver_option in analysis_options["driver"][
"options"
Expand Down
11 changes: 10 additions & 1 deletion ard/cost/orbit_wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,15 @@ def generate_orbit_location_from_graph(
for edge in edges_to_process:
node_countmap[edge[0]] += 1
node_countmap[edge[1]] += 1
if np.any(np.array(list(node_countmap.values())) > 2):
# if this has branching, handle it
if np.any(
(
np.array(list(node_countmap.values())) > 2
) # multiple turbine appearances indicates a branch
& (
np.array(list(node_countmap.keys())) >= 0
) # but substations do appear so "mask" them
):
if allow_branching_approximation:
warnings.warn(
"The provided collection system design graph includes branching, "
Expand Down Expand Up @@ -369,6 +377,7 @@ def compute(self, inputs, outputs, discrete_inputs, discrete_outputs):
if self._path_library:
initialize_library(self._path_library)

# send it back to the superclass compute
super().compute(
inputs,
outputs,
Expand Down
10 changes: 5 additions & 5 deletions ard/layout/boundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,16 @@ def setup(self):

# set up inputs and outputs for mooring system
self.add_input(
"x_turbines", jnp.zeros((self.N_turbines,)), units="km"
) # x location of the mooring platform in km w.r.t. reference coordinates
"x_turbines", jnp.zeros((self.N_turbines,)), units="m"
) # x location of the mooring platform in m w.r.t. reference coordinates
self.add_input(
"y_turbines", jnp.zeros((self.N_turbines,)), units="km"
) # y location of the mooring platform in km w.r.t. reference coordinates
"y_turbines", jnp.zeros((self.N_turbines,)), units="m"
) # y location of the mooring platform in m w.r.t. reference coordinates

self.add_output(
"boundary_distances",
jnp.zeros(self.N_turbines),
units="km",
units="m",
)

def setup_partials(self):
Expand Down
3 changes: 0 additions & 3 deletions ard/layout/fullfarm.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ class FullFarmLanduse(ard.layout.templates.LanduseTemplate):
modeling_options : dict
a modeling options dictionary (inherited from
`templates.LanduseTemplate`)
N_turbines : int
the number of turbines that should be in the farm layout (inherited from
`templates.LanduseTemplate`)

Inputs
------
Expand Down
4 changes: 0 additions & 4 deletions ard/layout/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ class LayoutTemplate(om.ExplicitComponent):
-------
modeling_options : dict
a modeling options dictionary
N_turbines : int
the number of turbines that should be in the farm layout

Inputs
------
Expand Down Expand Up @@ -104,8 +102,6 @@ class LanduseTemplate(om.ExplicitComponent):
-------
modeling_options : dict
a modeling options dictionary
N_turbines : int
the number of turbines that should be in the farm layout

Inputs
------
Expand Down
4 changes: 2 additions & 2 deletions ard/viz/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ def plot_layout(
windIO_dict = input_dict["modeling_options"]["windIO_plant"]

ax.fill(
[x * 1e3 for x in windIO_dict["site"]["boundaries"]["polygons"][0]["x"]],
[y * 1e3 for y in windIO_dict["site"]["boundaries"]["polygons"][0]["y"]],
windIO_dict["site"]["boundaries"]["polygons"][0]["x"],
windIO_dict["site"]["boundaries"]["polygons"][0]["y"],
linestyle="--",
alpha=0.5,
fill=False,
Expand Down
12 changes: 7 additions & 5 deletions test/system/ard/geometry/test_constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def setup_method(self):
"boundaries": {
"polygons": [
{
"x": [-2.0, 2.0, 2.0, -2.0],
"y": [-2.0, -2.0, 2.0, 2.0],
"x": [-2000.0, 2000.0, 2000.0, -2000.0],
"y": [-2000.0, -2000.0, 2000.0, 2000.0],
},
],
},
Expand Down Expand Up @@ -99,7 +99,9 @@ def test_constraint_evaluation(self, subtests):

# load validation data from pyrite file using ard.utils.io
validation_data = {
"boundary_distances": self.prob.get_val("boundary_distances"),
"boundary_distances": self.prob.get_val(
"boundary_distances", units="km"
),
}
with subtests.test(f"boundary_violations pyrite validation at {spacing}D"):
ard.utils.test_utils.pyrite_validator(
Expand Down Expand Up @@ -135,9 +137,9 @@ def test_constraint_optimization(self, subtests):

# after 10 iterations, should have near-zero boundary distances
with subtests.test("boundary distances near zero"):
tolerance_spec = 1.0e-3
assert np.all(
np.isclose(self.prob.get_val("boundary_distances"), 0.0)
| (self.prob.get_val("boundary_distances") < 0.0)
self.prob.get_val("boundary_distances", units="m") < tolerance_spec
)

# make sure the target spacing matches well
Expand Down
2 changes: 1 addition & 1 deletion test/unit/ard/cost/test_wisdem_wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def test_baseline_farm(self, subtests):
# Validate each key-value pair using subtests
for key, value in test_data.items():
with subtests.test(key=key):
assert np.isclose(value, pyrite_data[key], rtol=5e-3), (
assert np.allclose(value, pyrite_data[key], rtol=5e-3), (
f"Mismatch for {key}: " f"expected {pyrite_data[key]}, got {value}"
)

Expand Down
2 changes: 1 addition & 1 deletion test/unit/ard/farm_aero/test_floris.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ def test_compute_pyrite(self, subtests):
pyrite_data = ard.utils.test_utils.pyrite_validator(
test_data,
Path(__file__).parent / "test_floris_aep_pyrite.npz",
# rtol_val=5e-3, # check tol not needed when just loading data
# rtol_val=5e-3, # this parameter sets the relative tolerance for validation checks. Uncomment if needed.
# rewrite=True, # uncomment to write new pyrite file
load_only=True,
)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading