From ebd7e707afb385fa361940f4ea495a6fe7480fec Mon Sep 17 00:00:00 2001 From: nriccobo Date: Wed, 10 Jul 2024 13:14:43 -0600 Subject: [PATCH 01/10] Added CustomSemiSub class to semi_submersible_design.py --- .../phases/design/semi_submersible_design.py | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 23f0fd0c..1ea78d1e 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -208,3 +208,268 @@ def detailed_output(self): } return _outputs + + +"""Provides the `CustomSemiSubmersibleDesign` class.""" + +__author__ = "Matt Shields" +__copyright__ = "Copyright 2020, National Renewable Energy Laboratory" +__maintainer__ = "Nick Riccobono" +__email__ = "nicholas.riccobono@nrel.gov" + +import numpy as np + +from ORBIT.phases.design import DesignPhase + +""" +Based on semisub design from 15 MW RWT + +[1] C. Allen et al., “Definition of the UMaine VolturnUS-S Reference Platform + Developed for the IEA Wind 15-Megawatt Offshore Reference Wind Turbine,” + NREL/TP--5000-76773, 1660012, MainId:9434, Jul. 2020. doi: 10.2172/1660012. +[2] K. L. Roach, M. A. Lackner, and J. F. Manwell, “A New Methodology for + Upscaling Semi-submersible Platforms for Floating Offshore Wind Turbines,” + Wind Energy Science Discussions, pp. 1–33, Feb. 2023, + doi: 10.5194/wes-2023-18. +""" + + +class CustomSemiSubmersibleDesign(DesignPhase): + """Customized Semi-Submersible Substructure Design.""" + + expected_config = { + "site": {"depth": "m"}, + "plant": {"num_turbines": "int"}, + "turbine": {"turbine_rating": "MW"}, + "semisubmersible_design": { + "stiffened_column_CR": "$/t (optional, default: 3120)", + "truss_CR": "$/t (optional, default: 6250)", + "heave_plate_CR": "$/t (optional, default: 6250)", + "secondary_steel_CR": "$/t (optional, default: 7250)", + "towing_speed": "km/h (optional, default: 6)", + "column_diameter": "m", + "wall_thickness": "m", + "column_height": "m", + "pontoon_length": "m", + "pontoon_width": "m", + "pontoon_height": "m", + "strut_diameter": "m", + "steel_density": "kg/m^3 (optional, default: 8050)", + "ballast_mass": "tonnes (optional, default 0)", + "tower_interface_mass": "tonnes (optional, default 100)", + "steel_cost_rate": "$/tonne (optional, default: 4500)", + "ballast_material_CR": "$/tonne (optional, default: 150)", + }, + } + + output_config = { + "substructure": { + "mass": "t", + "unit_cost": "USD", + "towing_speed": "km/h", + } + } + + def __init__(self, config, **kwargs): + """ + Creates an instance of `CustomSemiSubmersibleDesign`. + + Parameters + ---------- + config : dict + """ + + config = self.initialize_library(config, **kwargs) + self.config = self.validate_config(config) + self._design = self.config.get("semisubmersible_design", {}) + + self.num_columns = kwargs.get("number_columns", 3) + + self._outputs = {} + + def run(self): + """Main run function.""" + + substructure = { + "mass": self.substructure_mass, + "unit_cost": self.substructure_unit_cost, + "towing_speed": self._design.get("towing_speed", 6), + } + + self._outputs["substructure"] = substructure + + def calc_geometric_scale_factor(self, **kwargs): + """Calculates the geometric factor to scale the size of the semi- + submersible. Upscaling methodology and parameters used are found on + Lines 335-340 [2]. + """ + + turbine_radius = float(self.config["turbine"]["rotor_diameter"] / 2) + + # IEA-15MW 120m radius + ref_radius = kwargs.get("ref_radius", 120.0) + + # power-law parameter + alpha = kwargs.get("alpha", 0.72) + + self.geom_scale_factor = (turbine_radius / ref_radius) ** alpha + + @property + def bouyant_column_volume(self): + """ + Returns the volume of a capped, hollow, cylindrical column, + assuming the wall-thickness remains constant [2]. + """ + + dc = self._design["column_diameter"] * self.geom_scale_factor + hc = self._design["column_height"] * self.geom_scale_factor + tc = self._design["wall_thickness"] + + return (np.pi / 4) * (hc * dc**2 - (hc - 2 * tc) * (dc - 2 * tc) ** 2) + + @property + def center_column_volume(self): + """ + Returns the volume of a hollow column between turbine and + pontoons, assuming wall-thickness remains constant [2]. + """ + + dc = 10.0 # fixed tower diameter + hc = self._design["column_height"] * self.geom_scale_factor + hp = self._design["pontoon_height"] * self.geom_scale_factor + tc = self._design["wall_thickness"] + + return (np.pi / 4) * ( + (hc - hp) * dc**2 - (hc - hp) * (dc - 2 * tc) ** 2 + ) + + @property + def pontoon_volume(self): + """ + Returns the volume of a single hollow rectangular pontoon that connects + the central column to the outer columns, assuming wall-thickness + reamins constant [2]. + """ + # TODO: Subtract semi-circular area from fairlead column? + + lp = self._design["pontoon_length"] * self.geom_scale_factor + wp = self._design["pontoon_width"] * self.geom_scale_factor + hp = self._design["pontoon_height"] * self.geom_scale_factor + tp = self._design["wall_thickness"] + + return (hp * wp - (hp - 2 * tp) * (wp - 2 * tp)) * lp + + @property + def strut_volume(self): + """ + Returns the volume of a single solid strut that connects + the central column to the outer columns. + """ + + lp = self._design["pontoon_length"] * self.geom_scale_factor + ds = self._design["strut_diameter"] * self.geom_scale_factor + + return (np.pi / 4) * (ds**2) * lp + + @property + def substructure_steel_mass(self): + """Returns the total mass of structural steel in the substructure.""" + + # TODO: Separate out different steels for each component + + density = self._design.get("steel_density", 7980) + + print( + "Volumes: ", + self.num_column * self.bouyant_column_volume, + self.center_column_volume, + self.num_column * self.pontoon_volume, + self.num_column * self.strut_volume, + ) + + return (density / 1000) * ( + self.num_column * self.bouyant_column_volume + + self.center_column_volume + + self.num_column * self.pontoon_volume + + self.num_column * self.strut_volume + ) + + @property + def ballast_mass(self): + """Returns the mass of fixed ballast. Default value from [1].""" + # TODO: Scale ballast mass with some factor? + # Fixed/Fluid needs to be addressed because 11,300t of seawater is used + # to submerge the platform. + + return self._design.get("ballast_mass", 2540) + + @property + def tower_interface_mass(self): + """Returns the mass of tower interface. Default value from [1].""" + + # TODO: Find a model to estimate the mass for a tower interface + + return self._design.get("tower_interface_mass", 100) + + @property + def substructure_steel_cost(self): + """Returns the total cost of structural steel of the substructure + in $USD. + """ + + steel_cr = self._design.get("steel_cost_rate", 4500) + + return steel_cr * self.substructure_steel_mass + + @property + def substructure_mass(self): + """ + Returns the total mass of structural steel and iron ore ballast + in the substructure. + """ + + return sum( + self.substructure_steel_mass, + self.ballast_mass, + self.tower_interface_mass, + ) + + @property + def substructure_unit_cost(self): + """ + Returns the total material cost of a single substructure. + Does not include final assembly or transportation costs. + """ + + ballast_cr = self._design.get("ballast_cost_rate", 150) + + return self.substructure_steel_cost + ballast_cr * self.ballast_mass + + @property + def design_result(self): + """Returns the result of `self.run()`.""" + + if not self._outputs: + raise Exception("Has `CustomSemiSubmersibleDesign` been ran yet?") + + return self._outputs + + @property + def total_cost(self): + """Returns total phase cost in $USD.""" + + num = self.config["plant"]["num_turbines"] + return num * self.substructure_unit_cost + + @property + def detailed_output(self): + """Returns detailed phase information.""" + + _outputs = { + "substructure_steel_mass": self.substructure_steel_mass, + "substructure_steel_cost": self.substructure_steel_cost, + "substructure_mass": self.substructure_mass, + "substructure_cost": self.substructure_unit_cost, + } + + return _outputs From d522a758c46a217cd75ebf380d47fb0a66c3cd88 Mon Sep 17 00:00:00 2001 From: nriccobo Date: Wed, 10 Jul 2024 16:11:04 -0600 Subject: [PATCH 02/10] Formatted custo semisub. Added to init --- ORBIT/phases/design/__init__.py | 5 ++++- .../phases/design/semi_submersible_design.py | 22 +++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/ORBIT/phases/design/__init__.py b/ORBIT/phases/design/__init__.py index 7871e0ca..69a37545 100644 --- a/ORBIT/phases/design/__init__.py +++ b/ORBIT/phases/design/__init__.py @@ -16,5 +16,8 @@ from .export_system_design import ExportSystemDesign from .mooring_system_design import MooringSystemDesign from .scour_protection_design import ScourProtectionDesign -from .semi_submersible_design import SemiSubmersibleDesign +from .semi_submersible_design import ( + SemiSubmersibleDesign, + CustomSemiSubmersibleDesign, +) from .SemiTaut_mooring_system_design import SemiTautMooringSystemDesign diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 1ea78d1e..0ae4eb8b 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -290,6 +290,8 @@ def __init__(self, config, **kwargs): def run(self): """Main run function.""" + self.calc_geometric_scale_factor() + substructure = { "mass": self.substructure_mass, "unit_cost": self.substructure_unit_cost, @@ -381,17 +383,17 @@ def substructure_steel_mass(self): print( "Volumes: ", - self.num_column * self.bouyant_column_volume, + self.bouyant_column_volume, self.center_column_volume, - self.num_column * self.pontoon_volume, - self.num_column * self.strut_volume, + self.pontoon_volume, + self.strut_volume, ) return (density / 1000) * ( - self.num_column * self.bouyant_column_volume + self.num_columns * self.bouyant_column_volume + self.center_column_volume - + self.num_column * self.pontoon_volume - + self.num_column * self.strut_volume + + self.num_columns * self.pontoon_volume + + self.num_columns * self.strut_volume ) @property @@ -429,9 +431,11 @@ def substructure_mass(self): """ return sum( - self.substructure_steel_mass, - self.ballast_mass, - self.tower_interface_mass, + [ + self.substructure_steel_mass, + self.ballast_mass, + self.tower_interface_mass, + ] ) @property From 1a5524c78efc7c7336ed8c938964352ac551a743 Mon Sep 17 00:00:00 2001 From: nriccobo Date: Fri, 19 Jul 2024 11:45:39 -0600 Subject: [PATCH 03/10] Added volturnus default geometries. --- .../phases/design/semi_submersible_design.py | 52 +++++++++++-------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 0ae4eb8b..2c7739d7 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -247,14 +247,14 @@ class CustomSemiSubmersibleDesign(DesignPhase): "heave_plate_CR": "$/t (optional, default: 6250)", "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", - "column_diameter": "m", - "wall_thickness": "m", - "column_height": "m", - "pontoon_length": "m", - "pontoon_width": "m", - "pontoon_height": "m", - "strut_diameter": "m", - "steel_density": "kg/m^3 (optional, default: 8050)", + "column_diameter": "m (optional, default: 12.5)", + "wall_thickness": "m (optional, default: 0.045)", + "column_height": "m (optional, default: 35)", + "pontoon_length": "m (optional, default: 51.75)", + "pontoon_width": "m (optional, default: 12.5)", + "pontoon_height": "m (optional, default: 7)", + "strut_diameter": "m (optional, 0.9)", + "steel_density": "kg/m^3 (optional, default: 7980)", "ballast_mass": "tonnes (optional, default 0)", "tower_interface_mass": "tonnes (optional, default 100)", "steel_cost_rate": "$/tonne (optional, default: 4500)", @@ -323,9 +323,9 @@ def bouyant_column_volume(self): assuming the wall-thickness remains constant [2]. """ - dc = self._design["column_diameter"] * self.geom_scale_factor - hc = self._design["column_height"] * self.geom_scale_factor - tc = self._design["wall_thickness"] + dc = self._design.get("column_diameter", 12.5) * self.geom_scale_factor + hc = self._design.get("column_height", 35) * self.geom_scale_factor + tc = self._design.get("wall_thickness", 0.045) return (np.pi / 4) * (hc * dc**2 - (hc - 2 * tc) * (dc - 2 * tc) ** 2) @@ -337,9 +337,9 @@ def center_column_volume(self): """ dc = 10.0 # fixed tower diameter - hc = self._design["column_height"] * self.geom_scale_factor - hp = self._design["pontoon_height"] * self.geom_scale_factor - tc = self._design["wall_thickness"] + hc = self._design.get("column_height", 35) * self.geom_scale_factor + hp = self._design.get("pontoon_height", 7) * self.geom_scale_factor + tc = self._design.get("wall_thickness", 0.045) return (np.pi / 4) * ( (hc - hp) * dc**2 - (hc - hp) * (dc - 2 * tc) ** 2 @@ -354,10 +354,10 @@ def pontoon_volume(self): """ # TODO: Subtract semi-circular area from fairlead column? - lp = self._design["pontoon_length"] * self.geom_scale_factor - wp = self._design["pontoon_width"] * self.geom_scale_factor - hp = self._design["pontoon_height"] * self.geom_scale_factor - tp = self._design["wall_thickness"] + lp = self._design.get("pontoon_length", 51.75) * self.geom_scale_factor + wp = self._design.get("pontoon_width", 12.5) * self.geom_scale_factor + hp = self._design.get("pontoon_height", 7) * self.geom_scale_factor + tp = self._design.get("wall_thickness", 0.045) return (hp * wp - (hp - 2 * tp) * (wp - 2 * tp)) * lp @@ -368,8 +368,8 @@ def strut_volume(self): the central column to the outer columns. """ - lp = self._design["pontoon_length"] * self.geom_scale_factor - ds = self._design["strut_diameter"] * self.geom_scale_factor + lp = self._design.get("pontoon_length", 51.75) * self.geom_scale_factor + ds = self._design.get("strut_diameter", 0.9) * self.geom_scale_factor return (np.pi / 4) * (ds**2) * lp @@ -419,9 +419,9 @@ def substructure_steel_cost(self): in $USD. """ - steel_cr = self._design.get("steel_cost_rate", 4500) + self.steel_cr = self._design.get("steel_cost_rate", 4500) - return steel_cr * self.substructure_steel_mass + return self.steel_cr * self.substructure_steel_mass @property def substructure_mass(self): @@ -447,7 +447,11 @@ def substructure_unit_cost(self): ballast_cr = self._design.get("ballast_cost_rate", 150) - return self.substructure_steel_cost + ballast_cr * self.ballast_mass + return ( + self.substructure_steel_cost + + ballast_cr * self.ballast_mass + + self.steel_cr * self.tower_interface_mass + ) @property def design_result(self): @@ -474,6 +478,8 @@ def detailed_output(self): "substructure_steel_cost": self.substructure_steel_cost, "substructure_mass": self.substructure_mass, "substructure_cost": self.substructure_unit_cost, + "ballast_mass": self.ballast_mass, + "tower_interface_mass": self.tower_interface_mass, } return _outputs From 57f38a1a63d4a14a3f57fb6f1a2a2eeffda0777e Mon Sep 17 00:00:00 2001 From: nriccobo Date: Tue, 23 Jul 2024 16:55:02 -0600 Subject: [PATCH 04/10] Updated CustomSemiSubmersible class with tests. --- .../phases/design/semi_submersible_design.py | 13 ++- .../config/semisubmersible_design_custom.yaml | 20 +++++ .../design/test_semisubmersible_design.py | 89 ++++++++++++++++++- 3 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 tests/data/library/project/config/semisubmersible_design_custom.yaml diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 2c7739d7..1a19f458 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -5,6 +5,7 @@ __maintainer__ = "Jake Nunemaker" __email__ = "jake.nunemaker@nrel.gov" +import numpy as np from ORBIT.phases.design import DesignPhase @@ -217,10 +218,6 @@ def detailed_output(self): __maintainer__ = "Nick Riccobono" __email__ = "nicholas.riccobono@nrel.gov" -import numpy as np - -from ORBIT.phases.design import DesignPhase - """ Based on semisub design from 15 MW RWT @@ -255,9 +252,9 @@ class CustomSemiSubmersibleDesign(DesignPhase): "pontoon_height": "m (optional, default: 7)", "strut_diameter": "m (optional, 0.9)", "steel_density": "kg/m^3 (optional, default: 7980)", - "ballast_mass": "tonnes (optional, default 0)", + "ballast_mass": "tonnes (optional, default 2540)", "tower_interface_mass": "tonnes (optional, default 100)", - "steel_cost_rate": "$/tonne (optional, default: 4500)", + "steel_CR": "$/tonne (optional, default: 4500)", "ballast_material_CR": "$/tonne (optional, default: 150)", }, } @@ -419,7 +416,7 @@ def substructure_steel_cost(self): in $USD. """ - self.steel_cr = self._design.get("steel_cost_rate", 4500) + self.steel_cr = self._design.get("steel_CR", 4500) return self.steel_cr * self.substructure_steel_mass @@ -445,7 +442,7 @@ def substructure_unit_cost(self): Does not include final assembly or transportation costs. """ - ballast_cr = self._design.get("ballast_cost_rate", 150) + ballast_cr = self._design.get("ballast_material_CR", 150) return ( self.substructure_steel_cost diff --git a/tests/data/library/project/config/semisubmersible_design_custom.yaml b/tests/data/library/project/config/semisubmersible_design_custom.yaml new file mode 100644 index 00000000..d30665f6 --- /dev/null +++ b/tests/data/library/project/config/semisubmersible_design_custom.yaml @@ -0,0 +1,20 @@ +plant: + num_turbines: 50 +site: + depth: 500 +turbine: + rotor_diameter: 220 + turbine_rating: 12 +semisubmersible_design: + column_diameter: 12.5 + wall_thickness": 0.0.045 + column_height": 35 + pontoon_length": 51.75 + pontoon_width": 12.5 + pontoon_height": 7 + strut_diameter": 0.9 + steel_density": 7980 + ballast_mass": 2540 + tower_interface_mass": 100 + steel_CR": 4500 + ballast_material_CR": 150 diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 2716d627..1e3d7cb2 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -9,7 +9,11 @@ import pytest -from ORBIT.phases.design import SemiSubmersibleDesign +from ORBIT.core.library import extract_library_specs +from ORBIT.phases.design import ( + SemiSubmersibleDesign, + CustomSemiSubmersibleDesign, +) base = { "site": {"depth": 500}, @@ -65,3 +69,86 @@ def test_design_kwargs(): cost = s.total_cost assert cost != base_cost + + +config_custom = extract_library_specs( + "config", "semisubmersible_design_custom" +) + + +def test_calc_geometric_scale_factor(): + pass + + +def test_bouyant_column_volume(): + pass + + +def test_center_column_volume(): + pass + + +def test_pontoon_volume(): + pass + + +def test_strut_volume(): + pass + + +def test_substructure_steel_mass(): + pass + + +def test_ballast_mass(): + pass + + +def test_tower_interface_mass(): + pass + + +def test_substructure_steel_cost(): + pass + + +def test_substructure_mass(): + pass + + +def test_substructure_unit_cost(): + pass + + +def test_custom_design_kwargs(): + + test_kwargs = { + "column_diameter": 15, + "wall_thickness": 0.1, + "column_height": 20, + "pontoon_length": 52, + "pontoon_width": 15, + "pontoon_height": 5, + "strut_diameter": 1.0, + "steel_density": 8500, + "ballast_mass": 1000, + "tower_interface_mass": 125, + "steel_CR": 3000, + "ballast_material_CR": 200, + } + + cust = CustomSemiSubmersibleDesign(config_custom) + cust.run() + base_cost = cust.total_cost + + for k, v in test_kwargs.items(): + + config = deepcopy(config_custom) + config["semisubmersible_design"] = {} + config["semisubmersible_design"][k] = v + + cust = CustomSemiSubmersibleDesign(config) + cust.run() + cost = cust.total_cost + + assert cost != base_cost From 6f701b15e83ab299fb379f82413a37217d2f7696 Mon Sep 17 00:00:00 2001 From: nriccobo Date: Wed, 24 Jul 2024 10:22:52 -0600 Subject: [PATCH 05/10] Updated custom semisub tests and cleaned up design module comments. --- .../phases/design/semi_submersible_design.py | 10 +-- .../config/semisubmersible_design_custom.yaml | 6 +- .../design/test_semisubmersible_design.py | 73 ++++++++++++++++--- 3 files changed, 66 insertions(+), 23 deletions(-) diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 1a19f458..f4939452 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -329,7 +329,7 @@ def bouyant_column_volume(self): @property def center_column_volume(self): """ - Returns the volume of a hollow column between turbine and + Returns the volume of a hollow cylindrical column between turbine and pontoons, assuming wall-thickness remains constant [2]. """ @@ -378,14 +378,6 @@ def substructure_steel_mass(self): density = self._design.get("steel_density", 7980) - print( - "Volumes: ", - self.bouyant_column_volume, - self.center_column_volume, - self.pontoon_volume, - self.strut_volume, - ) - return (density / 1000) * ( self.num_columns * self.bouyant_column_volume + self.center_column_volume diff --git a/tests/data/library/project/config/semisubmersible_design_custom.yaml b/tests/data/library/project/config/semisubmersible_design_custom.yaml index d30665f6..ec9e4ae6 100644 --- a/tests/data/library/project/config/semisubmersible_design_custom.yaml +++ b/tests/data/library/project/config/semisubmersible_design_custom.yaml @@ -3,11 +3,11 @@ plant: site: depth: 500 turbine: - rotor_diameter: 220 - turbine_rating: 12 + rotor_diameter: 240 + turbine_rating: 15 semisubmersible_design: column_diameter: 12.5 - wall_thickness": 0.0.045 + wall_thickness": 0.045 column_height": 35 pontoon_length": 51.75 pontoon_width": 12.5 diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 1e3d7cb2..6fd1c8f9 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -77,47 +77,98 @@ def test_design_kwargs(): def test_calc_geometric_scale_factor(): - pass + + config = deepcopy(config_custom) + + custom = CustomSemiSubmersibleDesign(config) + custom.run() + + assert custom.geom_scale_factor == 1.0 + + config["turbine"]["rotor_diameter"] = 220 + custom.run() + + assert custom.geom_scale_factor == pytest.approx(0.9392, 1e-4) def test_bouyant_column_volume(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.bouyant_column_volume == pytest.approx(72.5136, 1e-4) def test_center_column_volume(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.center_column_volume == pytest.approx(39.4059, 1e-4) def test_pontoon_volume(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.pontoon_volume == pytest.approx(90.4021, 1e-4) def test_strut_volume(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.strut_volume == pytest.approx(32.9219, 1e-4) def test_substructure_steel_mass(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.substructure_steel_mass == pytest.approx(5000, 1e0) def test_ballast_mass(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.ballast_mass == 2540 def test_tower_interface_mass(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.tower_interface_mass == 100 def test_substructure_steel_cost(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.steel_cr == 4500 def test_substructure_mass(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.substructure_mass == pytest.approx(7642, 1e0) def test_substructure_unit_cost(): - pass + + custom = CustomSemiSubmersibleDesign(config_custom) + custom.run() + + assert custom.substructure_unit_cost == pytest.approx(2.3343e7, 1e-4) def test_custom_design_kwargs(): From 05adb4a9de5cfe0500bd67b030f77b8c49cef315 Mon Sep 17 00:00:00 2001 From: nriccobo Date: Wed, 24 Jul 2024 11:25:58 -0600 Subject: [PATCH 06/10] Added a raise KeyError and test to semisub if no turbine diameter is specified --- ORBIT/phases/design/semi_submersible_design.py | 9 +++++++-- tests/phases/design/test_semisubmersible_design.py | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index f4939452..b8e744e8 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -303,7 +303,10 @@ def calc_geometric_scale_factor(self, **kwargs): Lines 335-340 [2]. """ - turbine_radius = float(self.config["turbine"]["rotor_diameter"] / 2) + turbine_diameter = self.config["turbine"].get("rotor_diameter") + + if turbine_diameter is None: + raise KeyError("Turbine rotor diameter not specified.") # IEA-15MW 120m radius ref_radius = kwargs.get("ref_radius", 120.0) @@ -311,7 +314,9 @@ def calc_geometric_scale_factor(self, **kwargs): # power-law parameter alpha = kwargs.get("alpha", 0.72) - self.geom_scale_factor = (turbine_radius / ref_radius) ** alpha + self.geom_scale_factor = ( + float(turbine_diameter) / 2 / ref_radius + ) ** alpha @property def bouyant_column_volume(self): diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 6fd1c8f9..28182251 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -90,6 +90,10 @@ def test_calc_geometric_scale_factor(): assert custom.geom_scale_factor == pytest.approx(0.9392, 1e-4) + with pytest.raises(KeyError): + config["turbine"]["rotor_diameter"] = None + custom.run() + def test_bouyant_column_volume(): From e5c9300203dc4d6f66eb1a243d8730c5901d92d0 Mon Sep 17 00:00:00 2001 From: nriccobo Date: Mon, 29 Jul 2024 11:47:52 -0600 Subject: [PATCH 07/10] Updated docs and changelog with semisub model. Also had to add it as a phase in manager. --- ORBIT/manager.py | 2 ++ docs/source/changelog.rst | 9 ++++++ .../design/doc_SemiSubmersibleDesign.rst | 30 ++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 84232f63..4c95be04 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -40,6 +40,7 @@ SemiSubmersibleDesign, CustomArraySystemDesign, OffshoreSubstationDesign, + CustomSemiSubmersibleDesign, SemiTautMooringSystemDesign, OffshoreFloatingSubstationDesign, ) @@ -80,6 +81,7 @@ class ProjectManager: MooringSystemDesign, SemiTautMooringSystemDesign, SemiSubmersibleDesign, + CustomSemiSubmersibleDesign, SparDesign, ElectricalDesign, ) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 92f5b249..613e403f 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -5,6 +5,15 @@ ORBIT Changelog Unreleased (TBD) ---------------- +Custom Semi-Submersible Design +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- The ``CustomSemiSubmersibleDesign`` class was added to semi_submersible_design.py. +- Based on VolturnUS-S by U-Maine. `https://www.nrel.gov/docs/fy20osti/76773.pdf` +- All design defaults are set to be consistent with 15MW IEA turbine +- Scaling logic added based on U-Mass paper. `https://wes.copernicus.org/preprints/wes-2023-18/wes-2023-18.pdf` +- Added tests to confirm that volumns and masses are calculated appropriately +- Added Example - Custom Semisubmersible notebook and yaml config file. +- Updated docs with citations. Merged SemiTaut Moorings ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/source/phases/design/doc_SemiSubmersibleDesign.rst b/docs/source/phases/design/doc_SemiSubmersibleDesign.rst index cd9ed924..e74729e5 100644 --- a/docs/source/phases/design/doc_SemiSubmersibleDesign.rst +++ b/docs/source/phases/design/doc_SemiSubmersibleDesign.rst @@ -11,8 +11,36 @@ The semi-submersible design module in ORBIT is based on previous modeling efforts undertaken by NREL, [#maness2017]_. The technical documentation for this tool can be found `here _`. +Custom Semi-Submersible Design Methodology +========================================== +For details of the code implementation, please see +:doc:`Semi-Submersible Design API `. + +(Custom) Overview +----------------- + +This new addition to ORBIT's semi-submersible design capabilities by letting +the user specify all the dimensions of the platform. IEAt was designed based on +the IEA-15MW reference turbine and the VolturnUS-S Reference Platform developed +by the University of Maine.[#allen2020]_.The triangular base uses three steel +columns equipped with ballast material. Each column is connected to a +central-column, where the turbine is afixed, by pontoons and spars. +Additionally, this new model uses the methodology proposed in [#roach2023]_ to +scale the platform to other turbine sizes. + References ---------- .. [#maness2017] Michael Maness, Benjamin Maples, Aaron Smith, - NREL Offshore Balance-of-System Model, 2017 + NREL Offshore Balance-of-System Model, 2017. + `https://www.nrel.gov/docs/fy17osti/66874.pdf` + +.. [#allen2020] Christopher Allen, Anthony Viselli, Habib Dagher, + Andrew Goupee, Evan Gaertner, Nikhar Abbas, Matthew Hall, + and Garrett Barter. Definition of the UMaine VolturnUS-S Reference Platform + Developed for the IEA Wind 15-Megawatt Offshore Reference Wind Turbine. + `https://www.nrel.gov/docs/fy20osti/76773.pdf` + +.. [#roach2023] Kaylie Roach, Matthew Lackner, James Manwell. A New Method for + Upscaling Semi-submersible Platforms for Floating Offshore Wind Turbines. + `https://wes.copernicus.org/preprints/wes-2023-18/wes-2023-18.pdf` From d3cabdda81f3e0d233d5366dd52132fd28c1e534 Mon Sep 17 00:00:00 2001 From: nriccobo Date: Wed, 31 Jul 2024 13:02:23 -0600 Subject: [PATCH 08/10] Updated the floating project example. --- examples/5. Example Floating Project.ipynb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/examples/5. Example Floating Project.ipynb b/examples/5. Example Floating Project.ipynb index 911922e2..5cc34315 100644 --- a/examples/5. Example Floating Project.ipynb +++ b/examples/5. Example Floating Project.ipynb @@ -20,7 +20,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "UserWarning: /var/folders/90/1lkt657x3n1cw5x65j3lfgd5406fb8/T/ipykernel_71795/2795185578.py:8\n", + "UserWarning: /var/folders/90/1lkt657x3n1cw5x65j3lfgd5406fb8/T/ipykernel_45285/2795185578.py:8\n", "Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format." ] } @@ -112,17 +112,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "ORBIT library intialized at '/Users/nriccobo/GitHub/ORBIT/library'\n", - "2\n" + "ORBIT library intialized at '/Users/nriccobo/GitHub/ORBIT/library'\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "DeprecationWarning: /Users/nriccobo/GitHub/ORBIT/ORBIT/phases/install/quayside_assembly_tow/moored.py:93\n", + "DeprecationWarning: /Users/nriccobo/GitHub/ORBIT/ORBIT/phases/install/quayside_assembly_tow/moored.py:94\n", "support_vessel will be deprecated and replaced with towing_vessels and ahts_vessel in the towing groups.\n", - "DeprecationWarning: /Users/nriccobo/GitHub/ORBIT/ORBIT/phases/install/quayside_assembly_tow/moored.py:93\n", + "DeprecationWarning: /Users/nriccobo/GitHub/ORBIT/ORBIT/phases/install/quayside_assembly_tow/moored.py:94\n", "['towing_vessl_groups]['station_keeping_vessels'] will be deprecated and replaced with ['towing_vessl_groups]['ahts_vessels'].\n" ] } @@ -149,10 +148,10 @@ "output_type": "stream", "text": [ "Installation CapEx: 519 M\n", - "System CapEx: 1333 M\n", + "System CapEx: 1440 M\n", "Turbine CapEx: 780 M\n", "Soft CapEx: 387 M\n", - "Total CapEx: 3171 M\n", + "Total CapEx: 3278 M\n", "\n", "Installation Time: 40914 h\n" ] @@ -187,7 +186,7 @@ " 'Export System': 432.13532047999996,\n", " 'Substructure': 1051.1827276666668,\n", " 'Mooring System': 545.7798,\n", - " 'Offshore Substation': 97.56143656207396,\n", + " 'Offshore Substation': 276.3947698954073,\n", " 'Array System Installation': 105.04624474280226,\n", " 'Export System Installation': 246.79354615177581,\n", " 'Substructure Installation': 208.2509277379141,\n", @@ -578,7 +577,7 @@ " 'mass': 1192.0,\n", " 'type': 'Floating',\n", " 'unit_cost': 3576000.0}\n", - "{'deck_space': 1, 'mass': 2980.0, 'unit_cost': 48411504.33724438}\n", + "{'deck_space': 1, 'mass': 2980.0, 'unit_cost': 155711504.3372444}\n", "{'anchor_cost': 139426.2,\n", " 'anchor_mass': 20,\n", " 'anchor_type': 'Drag Embedment',\n", @@ -623,7 +622,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.18" + "version": "3.10.14" } }, "nbformat": 4, From c9db0c6ae3360fd5239a7ce0aefe9c30dfe78e0b Mon Sep 17 00:00:00 2001 From: nriccobo Date: Thu, 1 Aug 2024 12:57:09 -0600 Subject: [PATCH 09/10] Updated get_cost calls in CustomSemiSub. Added defaults to common_cost --- ORBIT/core/defaults/common_costs.yaml | 2 ++ ORBIT/phases/design/semi_submersible_design.py | 15 ++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/ORBIT/core/defaults/common_costs.yaml b/ORBIT/core/defaults/common_costs.yaml index 1e8e9867..9458d821 100644 --- a/ORBIT/core/defaults/common_costs.yaml +++ b/ORBIT/core/defaults/common_costs.yaml @@ -66,6 +66,8 @@ semisubmersible_design: truss_CR: 6250 # USD/t heave_plate_CR: 6250 # USD/t secondary_steel_CR: 7250 # USD/t + steel_CR: 4500 # USD/t *CustomSemiSub* + ballast_material_CR: 150 # Mooring system component cost rates mooring_system_design: # USD/m diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 167d1c90..52d0aefe 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -252,10 +252,6 @@ class CustomSemiSubmersibleDesign(DesignPhase): "plant": {"num_turbines": "int"}, "turbine": {"turbine_rating": "MW"}, "semisubmersible_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", - "truss_CR": "$/t (optional, default: 6250)", - "heave_plate_CR": "$/t (optional, default: 6250)", - "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", "column_diameter": "m (optional, default: 12.5)", "wall_thickness": "m (optional, default: 0.045)", @@ -426,8 +422,10 @@ def substructure_steel_cost(self): in $USD. """ - self.steel_cr = self._design.get("steel_CR", 4500) - + _key = "steel_CR" + self.steel_cr = self._design.get( + _key, self.get_default_cost("semisubmersible_design", _key) + ) return self.steel_cr * self.substructure_steel_mass @property @@ -452,7 +450,10 @@ def substructure_unit_cost(self): Does not include final assembly or transportation costs. """ - ballast_cr = self._design.get("ballast_material_CR", 150) + _key = "ballast_material_CR" + ballast_cr = self._design.get( + _key, self.get_default_cost("semisubmersible_design", _key) + ) return ( self.substructure_steel_cost From f3c39a94383762b60724bd1e7aa90cd81f1865ee Mon Sep 17 00:00:00 2001 From: nriccobo Date: Fri, 13 Sep 2024 12:47:17 -0600 Subject: [PATCH 10/10] Updated a custom semisub example and config file. --- .../Example - Custom Semisubmersible.ipynb | 624 ++++++++++++++++++ examples/configs/custom_floating_project.yaml | 72 ++ 2 files changed, 696 insertions(+) create mode 100644 examples/Example - Custom Semisubmersible.ipynb create mode 100644 examples/configs/custom_floating_project.yaml diff --git a/examples/Example - Custom Semisubmersible.ipynb b/examples/Example - Custom Semisubmersible.ipynb new file mode 100644 index 00000000..81659f62 --- /dev/null +++ b/examples/Example - Custom Semisubmersible.ipynb @@ -0,0 +1,624 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Custom Floating Project\n", + "\n", + "This tutorial uses the prepared ORBIT config file `~/configs/custom_floating_project.yaml`. This example uses `ParametricManager()` to sweep different turbine sizes to demonstrate the scaling abilities of the `CustomSemiSubmersibleDesign()` class. \n", + "\n", + "Last updated: July 2024" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "UserWarning: /var/folders/90/1lkt657x3n1cw5x65j3lfgd5406fb8/T/ipykernel_45622/3200251840.py:5\n", + "Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format." + ] + } + ], + "source": [ + "import pandas as pd\n", + "from pprint import pprint\n", + "from ORBIT import load_config, ProjectManager, ParametricManager\n", + "\n", + "weather = pd.read_csv(\"data/example_weather.csv\", parse_dates=[\"datetime\"])\\\n", + " .set_index(\"datetime\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Load the project configuration\n", + "`~/configs/custom_floating_project.yaml`" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Num turbines: 50\n", + "Turbine: 12MW_generic\n", + "\n", + "Site: {'depth': 900, 'distance': 100, 'distance_to_landfall': 100}\n" + ] + } + ], + "source": [ + "floating_config = load_config(\"configs/custom_floating_project.yaml\")\n", + "\n", + "print(f\"Num turbines: {floating_config['plant']['num_turbines']}\")\n", + "print(f\"Turbine: {floating_config['turbine']}\")\n", + "print(f\"\\nSite: {floating_config['site']}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Phases" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Design phases:\n", + "\n", + "['ArraySystemDesign',\n", + " 'ElectricalDesign',\n", + " 'MooringSystemDesign',\n", + " 'OffshoreSubstationDesign',\n", + " 'CustomSemiSubmersibleDesign']\n", + "\n", + "Install phases: \n", + "\n", + "['ArrayCableInstallation',\n", + " 'ExportCableInstallation',\n", + " 'MooredSubInstallation',\n", + " 'MooringSystemInstallation',\n", + " 'FloatingSubstationInstallation',\n", + " 'TurbineInstallation']\n" + ] + } + ], + "source": [ + "print(\"Design phases:\\n\")\n", + "pprint(floating_config['design_phases'])\n", + "print(f\"\\nInstall phases: \\n\")\n", + "pprint(list(floating_config['install_phases'].keys()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Run" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "project = ProjectManager(floating_config, weather=weather)\n", + "project.run()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Top Level Outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installation CapEx: 519 M\n", + "System CapEx: 1805 M\n", + "Turbine CapEx: 780 M\n", + "Soft CapEx: 387 M\n", + "Total CapEx: 3643 M\n", + "\n", + "Installation Time: 40914 h\n" + ] + } + ], + "source": [ + "print(f\"Installation CapEx: {project.installation_capex/1e6:.0f} M\")\n", + "print(f\"System CapEx: {project.system_capex/1e6:.0f} M\")\n", + "print(f\"Turbine CapEx: {project.turbine_capex/1e6:.0f} M\")\n", + "print(f\"Soft CapEx: {project.soft_capex/1e6:.0f} M\")\n", + "print(f\"Total CapEx: {project.total_capex/1e6:.0f} M\")\n", + "\n", + "print(f\"\\nInstallation Time: {project.installation_time:.0f} h\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### CapEx Breakdown" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'Array System': 94.97179434403438,\n", + " 'Export System': 432.13532047999996,\n", + " 'Substructure': 1659.0582404215481,\n", + " 'Mooring System': 545.7798,\n", + " 'Offshore Substation': 276.3947698954073,\n", + " 'Array System Installation': 105.04624474280226,\n", + " 'Export System Installation': 246.79354615177581,\n", + " 'Substructure Installation': 208.2509277379141,\n", + " 'Mooring System Installation': 80.80888508371386,\n", + " 'Offshore Substation Installation': 11.784658802638255,\n", + " 'Turbine Installation': 212.89678462709279,\n", + " 'Turbine': 1300.0,\n", + " 'Soft': 645.0,\n", + " 'Project': 252.08333333333334}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "project.capex_breakdown_per_kw" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Installation Actions" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
cost_multiplieragentactiondurationcostleveltimephaselocationsite_depthhub_heightphase_namemax_waveheightmax_windspeedtransit_speednum_vesselsnum_ahts_vessels
00.5Array Cable Installation VesselMobilize72.0000003.375000e+05ACTION0.000000ArrayCableInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
10.5Export Cable Installation VesselMobilize72.0000003.375000e+05ACTION0.000000ExportCableInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
2NaNOnshore ConstructionOnshore Construction0.0000001.665604e+06ACTION0.000000ExportCableInstallationLandfallNaNNaNNaNNaNNaNNaNNaNNaN
31.0Mooring System Installation VesselMobilize168.0000007.000000e+05ACTION0.000000MooringSystemInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
4NaNSubstation Assembly Line 1Substation Substructure Assembly0.0000000.000000e+00ACTION0.000000FloatingSubstationInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
......................................................
4458NaNExport Cable Installation VesselPull In Cable5.5000005.156250e+04ACTION12017.280762ExportCableInstallationNaNNaNNaNExportCableInstallationNaNNaNNaNNaNNaN
4459NaNExport Cable Installation VesselTerminate Cable5.5000005.156250e+04ACTION12022.780762ExportCableInstallationNaNNaNNaNExportCableInstallationNaNNaNNaNNaNNaN
4460NaNExport Cable Installation VesselTransit8.0000007.500000e+04ACTION12030.780762ExportCableInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
4461NaNExport Cable Installation VesselDelay26.0000002.437500e+05ACTION12056.780762ExportCableInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
4462NaNExport Cable Installation VesselTransit0.6956526.521739e+03ACTION12057.476414ExportCableInstallationNaNNaNNaNNaNNaNNaNNaNNaNNaN
\n", + "

4463 rows \u00d7 17 columns

\n", + "
" + ], + "text/plain": [ + " cost_multiplier agent \\\n", + "0 0.5 Array Cable Installation Vessel \n", + "1 0.5 Export Cable Installation Vessel \n", + "2 NaN Onshore Construction \n", + "3 1.0 Mooring System Installation Vessel \n", + "4 NaN Substation Assembly Line 1 \n", + "... ... ... \n", + "4458 NaN Export Cable Installation Vessel \n", + "4459 NaN Export Cable Installation Vessel \n", + "4460 NaN Export Cable Installation Vessel \n", + "4461 NaN Export Cable Installation Vessel \n", + "4462 NaN Export Cable Installation Vessel \n", + "\n", + " action duration cost level \\\n", + "0 Mobilize 72.000000 3.375000e+05 ACTION \n", + "1 Mobilize 72.000000 3.375000e+05 ACTION \n", + "2 Onshore Construction 0.000000 1.665604e+06 ACTION \n", + "3 Mobilize 168.000000 7.000000e+05 ACTION \n", + "4 Substation Substructure Assembly 0.000000 0.000000e+00 ACTION \n", + "... ... ... ... ... \n", + "4458 Pull In Cable 5.500000 5.156250e+04 ACTION \n", + "4459 Terminate Cable 5.500000 5.156250e+04 ACTION \n", + "4460 Transit 8.000000 7.500000e+04 ACTION \n", + "4461 Delay 26.000000 2.437500e+05 ACTION \n", + "4462 Transit 0.695652 6.521739e+03 ACTION \n", + "\n", + " time phase location site_depth \\\n", + "0 0.000000 ArrayCableInstallation NaN NaN \n", + "1 0.000000 ExportCableInstallation NaN NaN \n", + "2 0.000000 ExportCableInstallation Landfall NaN \n", + "3 0.000000 MooringSystemInstallation NaN NaN \n", + "4 0.000000 FloatingSubstationInstallation NaN NaN \n", + "... ... ... ... ... \n", + "4458 12017.280762 ExportCableInstallation NaN NaN \n", + "4459 12022.780762 ExportCableInstallation NaN NaN \n", + "4460 12030.780762 ExportCableInstallation NaN NaN \n", + "4461 12056.780762 ExportCableInstallation NaN NaN \n", + "4462 12057.476414 ExportCableInstallation NaN NaN \n", + "\n", + " hub_height phase_name max_waveheight max_windspeed \\\n", + "0 NaN NaN NaN NaN \n", + "1 NaN NaN NaN NaN \n", + "2 NaN NaN NaN NaN \n", + "3 NaN NaN NaN NaN \n", + "4 NaN NaN NaN NaN \n", + "... ... ... ... ... \n", + "4458 NaN ExportCableInstallation NaN NaN \n", + "4459 NaN ExportCableInstallation NaN NaN \n", + "4460 NaN NaN NaN NaN \n", + "4461 NaN NaN NaN NaN \n", + "4462 NaN NaN NaN NaN \n", + "\n", + " transit_speed num_vessels num_ahts_vessels \n", + "0 NaN NaN NaN \n", + "1 NaN NaN NaN \n", + "2 NaN NaN NaN \n", + "3 NaN NaN NaN \n", + "4 NaN NaN NaN \n", + "... ... ... ... \n", + "4458 NaN NaN NaN \n", + "4459 NaN NaN NaN \n", + "4460 NaN NaN NaN \n", + "4461 NaN NaN NaN \n", + "4462 NaN NaN NaN \n", + "\n", + "[4463 rows x 17 columns]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.DataFrame(project.actions)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'deck_space': 1,\n", + " 'length': 0,\n", + " 'mass': 1192.0,\n", + " 'type': 'Floating',\n", + " 'unit_cost': 3576000.0}\n", + "{'deck_space': 1, 'mass': 2980.0, 'unit_cost': 155711504.3372444}\n", + "{'anchor_cost': 139426.2,\n", + " 'anchor_mass': 20,\n", + " 'anchor_type': 'Drag Embedment',\n", + " 'line_cost': 1497913.2,\n", + " 'line_diam': 0.15,\n", + " 'line_length': 1755.71,\n", + " 'line_mass': 579.8762530880001,\n", + " 'mooring_type': 'SemiTaut',\n", + " 'num_lines': 4,\n", + " 'system_cost': 327467880.0}\n", + "'Mooring System: $/kW'\n", + "545.7798\n", + "80.80888508371386\n" + ] + } + ], + "source": [ + "pprint(project.design_results[\"offshore_substation_substructure\"])\n", + "pprint(project.design_results[\"offshore_substation_topside\"])\n", + "pprint(project.design_results[\"mooring_system\"])\n", + "\n", + "pprint(\"Mooring System: $/kW\")\n", + "pprint(project.capex_breakdown_per_kw['Mooring System'])\n", + "\n", + "pprint(project.capex_breakdown_per_kw['Mooring System Installation'])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/configs/custom_floating_project.yaml b/examples/configs/custom_floating_project.yaml new file mode 100644 index 00000000..85dc572f --- /dev/null +++ b/examples/configs/custom_floating_project.yaml @@ -0,0 +1,72 @@ +# Site + Plant Parameters +site: + depth: 900 + distance: 100 + distance_to_landfall: 100 +plant: + layout: ring + num_turbines: 50 + row_spacing: 7 + substation_distance: 1 + turbine_spacing: 7 +port: + monthly_rate: 2000000.0 + sub_assembly_lines: 1 + turbine_assembly_cranes: 1 +# Vessels +array_cable_install_vessel: example_cable_lay_vessel +export_cable_install_vessel: example_cable_lay_vessel +mooring_install_vessel: example_support_vessel +oss_install_vessel: floating_heavy_lift_vessel +support_vessel: example_support_vessel +ahts_vessel: example_ahts_vessel +towing_vessel: example_towing_vessel +towing_vessel_groups: + station_keeping_vessels: 2 + towing_vessels: 3 +wtiv: floating_heavy_lift_vessel +# Module Specific +substructure: + takt_time: 168 +substation_design: + oss_substructure_type: Floating +mooring_system_design: + anchor_type: Drag Embedment + mooring_type: SemiTaut +array_system: + free_cable_length: 0.5 +array_system_design: + cables: + - XLPE_630mm_66kV +export_system_design: + cables: XLPE_500mm_132kV + percent_added_length: 0.0 +# Based on U-Maine/U-Mass references IEA-15MW 4.5cm for IEA scale, 3.2cm to match Umaine +semisubmersible_design: + column_diameter: 12.5 + wall_thickness: 0.045 + column_height: 35 + pontoon_length: 51.75 + pontoon_width: 12.5 + pontoon_height: 7 + strut_diameter: 0.9 + ballast_mass: 2540 + tower_interface_mass : 100 + steel_CR: 4500 + ballast_material_CR: 150 +# Configured Phases +design_phases: +- ArraySystemDesign +- ElectricalDesign +- MooringSystemDesign +- OffshoreSubstationDesign +- CustomSemiSubmersibleDesign +install_phases: + ArrayCableInstallation: 0 + ExportCableInstallation: 0 + MooredSubInstallation: 0 + MooringSystemInstallation: 0 + FloatingSubstationInstallation: 0 + TurbineInstallation: 0 +# Project Inputs +turbine: 12MW_generic