diff --git a/ard/api/interface.py b/ard/api/interface.py index 27ffcf79..fd08acbd 100644 --- a/ard/api/interface.py +++ b/ard/api/interface.py @@ -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, @@ -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, @@ -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: @@ -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" diff --git a/ard/cost/orbit_wrap.py b/ard/cost/orbit_wrap.py index 0709b25c..4523167d 100644 --- a/ard/cost/orbit_wrap.py +++ b/ard/cost/orbit_wrap.py @@ -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, " @@ -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, diff --git a/ard/layout/boundary.py b/ard/layout/boundary.py index 1de2a62e..dadc3183 100644 --- a/ard/layout/boundary.py +++ b/ard/layout/boundary.py @@ -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): diff --git a/ard/layout/fullfarm.py b/ard/layout/fullfarm.py index 383b5348..fb73bb8a 100644 --- a/ard/layout/fullfarm.py +++ b/ard/layout/fullfarm.py @@ -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 ------ diff --git a/ard/layout/templates.py b/ard/layout/templates.py index b0583354..3178b0ba 100644 --- a/ard/layout/templates.py +++ b/ard/layout/templates.py @@ -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 ------ @@ -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 ------ diff --git a/ard/viz/layout.py b/ard/viz/layout.py index ee8c102d..1cb7c325 100644 --- a/ard/viz/layout.py +++ b/ard/viz/layout.py @@ -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, diff --git a/examples/03_offshore_floating/inputs/ard_system.yaml b/examples/03_offshore_floating_custom_system/inputs/ard_system.yaml similarity index 100% rename from examples/03_offshore_floating/inputs/ard_system.yaml rename to examples/03_offshore_floating_custom_system/inputs/ard_system.yaml diff --git a/examples/03_offshore_floating/inputs/windio.yaml b/examples/03_offshore_floating_custom_system/inputs/windio.yaml similarity index 100% rename from examples/03_offshore_floating/inputs/windio.yaml rename to examples/03_offshore_floating_custom_system/inputs/windio.yaml diff --git a/examples/03_offshore_floating/optimization_demo.py b/examples/03_offshore_floating_custom_system/optimization_demo.py similarity index 100% rename from examples/03_offshore_floating/optimization_demo.py rename to examples/03_offshore_floating_custom_system/optimization_demo.py diff --git a/test/system/ard/geometry/test_constraints.py b/test/system/ard/geometry/test_constraints.py index 1fc22789..1ae0646c 100644 --- a/test/system/ard/geometry/test_constraints.py +++ b/test/system/ard/geometry/test_constraints.py @@ -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], }, ], }, @@ -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( @@ -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 diff --git a/test/unit/ard/cost/test_wisdem_wrap.py b/test/unit/ard/cost/test_wisdem_wrap.py index b7486a57..8d4ae901 100644 --- a/test/unit/ard/cost/test_wisdem_wrap.py +++ b/test/unit/ard/cost/test_wisdem_wrap.py @@ -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}" ) diff --git a/test/unit/ard/farm_aero/test_floris.py b/test/unit/ard/farm_aero/test_floris.py index c9b04877..b1ead512 100644 --- a/test/unit/ard/farm_aero/test_floris.py +++ b/test/unit/ard/farm_aero/test_floris.py @@ -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, ) diff --git a/test/unit/utils/test_geometry.py b/test/unit/ard/utils/utils/test_geometry.py similarity index 100% rename from test/unit/utils/test_geometry.py rename to test/unit/ard/utils/utils/test_geometry.py diff --git a/test/unit/utils/test_io.py b/test/unit/ard/utils/utils/test_io.py similarity index 100% rename from test/unit/utils/test_io.py rename to test/unit/ard/utils/utils/test_io.py diff --git a/test/unit/utils/test_matematics.py b/test/unit/ard/utils/utils/test_matematics.py similarity index 100% rename from test/unit/utils/test_matematics.py rename to test/unit/ard/utils/utils/test_matematics.py diff --git a/test/unit/utils/test_utils.py b/test/unit/ard/utils/utils/test_utils.py similarity index 100% rename from test/unit/utils/test_utils.py rename to test/unit/ard/utils/utils/test_utils.py