From 8800d5207420681f8774fe0360c8d51d2e4ec779 Mon Sep 17 00:00:00 2001 From: Jake Nunemaker Date: Tue, 20 Dec 2022 19:34:15 -0700 Subject: [PATCH 01/19] Added explict method for registering custom phases. Added tests for validations and successful registration. --- ORBIT/manager.py | 48 +++++++++++++++++++++ tests/test_project_manager.py | 78 +++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 769a7b9a..b1460923 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -188,6 +188,54 @@ def phases(self): return self._phases + @classmethod + def register_design_phase(cls, phase): + """ + Add a custom design phase to the `ProjectManager` class. + + Parameters + ---------- + phase : ORBIT.phases.DesignPhase + """ + + if not issubclass(phase, DesignPhase): + raise ValueError( + "Registered design phase must be a subclass of " + "'ORBIT.phases.DesignPhase'." + ) + + if phase.__name__ in [c.__name__ for c in cls._design_phases]: + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + + if len(re.split("[_ ]", phase.__name__)) > 1: + raise ValueError(f"Registered phase name must not include a '_'.") + + cls._design_phases.append(phase) + + @classmethod + def register_install_phase(cls, phase): + """ + Add a custom install phase to the `ProjectManager` class. + + Parameters + ---------- + phase : ORBIT.phases.InstallPhase + """ + + if not issubclass(phase, InstallPhase): + raise ValueError( + "Registered install phase must be a subclass of " + "'ORBIT.phases.InstallPhase'." + ) + + if phase.__name__ in [c.__name__ for c in cls._install_phases]: + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + + if len(re.split("[_ ]", phase.__name__)) > 1: + raise ValueError(f"Registered phase name must not include a '_'.") + + cls._install_phases.append(phase) + @property def _capex_categories(self): """Returns CapEx categories for phases in `self._install_phases`.""" diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 2e96979e..0ac2c8c0 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -10,6 +10,7 @@ import pytest from ORBIT import ProjectManager +from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs @@ -281,6 +282,83 @@ def test_duplicate_phase_definitions(): assert df.loc[("TurbineInstallation", "Attach Tower Section")] == 10 +def test_custom_install_phases(): + + # Not a subclass + class CustomInstallPhase: + pass + + with pytest.raises(ValueError): + ProjectManager.register_design_phase(CustomInstallPhase) + + # Wrong subclass + class CustomDesignPhase(DesignPhase): + pass + + with pytest.raises(ValueError): + ProjectManager.register_install_phase(CustomDesignPhase) + + # Name already taken + class MonopileInstallation(InstallPhase): + pass + + with pytest.raises(ValueError): + ProjectManager.register_install_phase(MonopileInstallation) + + + # Bad name format + class MonopileInstallation_Custom(InstallPhase): + pass + + with pytest.raises(ValueError): + ProjectManager.register_install_phase(MonopileInstallation_Custom) + + # Successful registration + class CustomInstallPhase(InstallPhase): + pass + + ProjectManager.register_install_phase(CustomInstallPhase) + assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase + + +def test_custom_design_phases(): + + # Not a subclass + class CustomDesignPhase: + pass + + with pytest.raises(ValueError): + ProjectManager.register_design_phase(CustomDesignPhase) + + # Wrong subclass + class CustomInstallPhase(InstallPhase): + pass + + with pytest.raises(ValueError): + ProjectManager.register_design_phase(CustomInstallPhase) + + # Name already taken + class MonopileDesign(DesignPhase): + pass + + with pytest.raises(ValueError): + ProjectManager.register_install_phase(MonopileDesign) + + + # Bad name format + class MonopileDesign_Custom(DesignPhase): + pass + + with pytest.raises(ValueError): + ProjectManager.register_install_phase(MonopileDesign_Custom) + + # Successful registration + class CustomDesignPhase(DesignPhase): + pass + + ProjectManager.register_design_phase(CustomDesignPhase) + assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + ### Design Phase Interactions def test_design_phases(): From cc421788aad456b8e2f87ccdad9f58ba3201a171 Mon Sep 17 00:00:00 2001 From: Jake Nunemaker Date: Wed, 21 Dec 2022 14:46:15 -0800 Subject: [PATCH 02/19] Revised dtype for design and install phases to limit direct appending of custom phases. --- ORBIT/manager.py | 12 ++++++------ tests/test_project_manager.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index b1460923..6aeb5ba1 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -61,7 +61,7 @@ class ProjectManager: date_format_short = "%m/%d/%Y" date_format_long = "%m/%d/%Y %H:%M" - _design_phases = [ + _design_phases = ( MonopileDesign, ArraySystemDesign, CustomArraySystemDesign, @@ -71,9 +71,9 @@ class ProjectManager: MooringSystemDesign, SemiSubmersibleDesign, SparDesign, - ] + ) - _install_phases = [ + _install_phases = ( MonopileInstallation, TurbineInstallation, OffshoreSubstationInstallation, @@ -85,7 +85,7 @@ class ProjectManager: GravityBasedInstallation, FloatingSubstationInstallation, JacketInstallation, - ] + ) def __init__(self, config, library_path=None, weather=None): """ @@ -210,7 +210,7 @@ def register_design_phase(cls, phase): if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") - cls._design_phases.append(phase) + cls._design_phases = (*cls._design_phases, phase) @classmethod def register_install_phase(cls, phase): @@ -234,7 +234,7 @@ def register_install_phase(cls, phase): if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") - cls._install_phases.append(phase) + cls._install_phases = (*cls._install_phases, phase) @property def _capex_categories(self): diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 0ac2c8c0..7e62a225 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -109,11 +109,11 @@ def test_expected_config_merging(): def test_find_key_match(): - class SpecificTurbineInstallation: + class SpecificTurbineInstallation(InstallPhase): expected_config = {} TestProjectManager = deepcopy(ProjectManager) - TestProjectManager._install_phases.append(SpecificTurbineInstallation) + TestProjectManager.register_install_phase(SpecificTurbineInstallation) phase_dict = TestProjectManager.phase_dict() assert "SpecificTurbineInstallation" in phase_dict.keys() From db977df8299d65c5969264dad1a427d30e403cc6 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 22 Feb 2023 19:35:57 -0700 Subject: [PATCH 03/19] fix bug that causes error with >2 substations --- ORBIT/phases/design/array_system_design.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 1a25ab9f..ba95c99e 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -1017,7 +1017,7 @@ def _create_windfarm_layout(self): self.sections_bury_speeds[ string, order ] = data.bury_speed.values[order] - i += string + 1 + i = string + 1 # Ensure any point in array without a turbine is set to None no_turbines = self.location_data_x == 0 From c870e8333ab9571c75d100057d15a825f2aea142 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 22 Feb 2023 19:36:30 -0700 Subject: [PATCH 04/19] fix issue with unnecessary commas in error message --- ORBIT/phases/design/array_system_design.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index ba95c99e..be00adbb 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -851,8 +851,8 @@ def _initialize_custom_data(self): missing = set(self.COLUMNS).difference(self.location_data.columns) if missing: raise ValueError( - "The following columns must be included in the location ", - f"data: {missing}", + "The following columns must be included in the location " + f"data: {missing}" ) self._format_windfarm_data() @@ -885,9 +885,9 @@ def _initialize_custom_data(self): # Ensure the number of turbines matches what's expected if self.location_data.shape[0] != self.system.num_turbines: raise ValueError( - "The provided number of turbines ", - f"({self.location_data.shape[0]}) does not match the plant ", - f"data ({self.system.num_turbines}).", + "The provided number of turbines " + f"({self.location_data.shape[0]}) does not match the plant " + f"data ({self.system.num_turbines})." ) n_coords = self.location_data.groupby( From 1af5efb4c2d1466babc18d18fc2e767d69c48015 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 22 Feb 2023 19:41:19 -0700 Subject: [PATCH 05/19] add additional library loading location --- ORBIT/phases/design/array_system_design.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 1a25ab9f..5f349ed1 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -843,10 +843,14 @@ def _format_windfarm_data(self): def _initialize_custom_data(self): windfarm = self.config["array_system_design"]["location_data"] - self.location_data = extract_library_specs( - "cables", windfarm, file_type="csv" - ) - + try: + self.location_data = extract_library_specs( + "cables", windfarm, file_type="csv" + ) + except LibraryItemNotFoundError: + self.location_data = extract_library_specs( + "project/plant", windfarm, file_type="csv" + ) # Make sure no data is missing missing = set(self.COLUMNS).difference(self.location_data.columns) if missing: From e86ef2461e6dcf36179de0add7b6eea021a8f87d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 17:25:03 +0000 Subject: [PATCH 06/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++++---- ORBIT/api/wisdem.py | 1 - ORBIT/config.py | 1 - ORBIT/core/cargo.py | 1 - ORBIT/core/components.py | 1 - ORBIT/core/defaults/__init__.py | 1 - ORBIT/core/environment.py | 2 - ORBIT/core/exceptions.py | 1 - ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 - ORBIT/core/port.py | 1 - ORBIT/core/supply_chain.py | 1 - ORBIT/core/vessel.py | 2 - ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 - ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 4 - ORBIT/phases/design/export_system_design.py | 2 - ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 - ORBIT/phases/install/cable_install/common.py | 1 - ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 - ORBIT/phases/install/jacket_install/common.py | 1 - .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 - .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 - ORBIT/phases/install/oss_install/common.py | 2 - ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 - .../quayside_assembly_tow/gravity_base.py | 3 - .../install/quayside_assembly_tow/moored.py | 3 - .../scour_protection_install/standard.py | 1 - .../phases/install/turbine_install/common.py | 1 - .../install/turbine_install/standard.py | 4 - ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 +++++++---- templates/design_module.py | 74 +++-- tests/api/test_wisdem_api.py | 3 - tests/conftest.py | 9 - tests/core/test_environment.py | 1 - tests/core/test_library.py | 2 - tests/core/test_port.py | 3 - .../phases/design/test_array_system_design.py | 2 - tests/phases/design/test_cable.py | 2 - .../design/test_export_system_design.py | 2 - tests/phases/design/test_monopile_design.py | 6 - .../design/test_mooring_system_design.py | 5 - tests/phases/design/test_oss_design.py | 4 - .../design/test_scour_protection_design.py | 1 - .../design/test_semisubmersible_design.py | 4 - tests/phases/design/test_spar_design.py | 4 - .../cable_install/test_array_install.py | 10 - .../install/cable_install/test_cable_tasks.py | 3 - .../cable_install/test_export_install.py | 10 - .../jacket_install/test_jacket_install.py | 10 - .../monopile_install/test_monopile_install.py | 9 - .../monopile_install/test_monopile_tasks.py | 3 - .../mooring_install/test_mooring_install.py | 5 - .../install/oss_install/test_oss_install.py | 10 - .../install/oss_install/test_oss_tasks.py | 3 - .../quayside_assembly_tow/test_common.py | 4 - .../test_gravity_based.py | 3 - .../quayside_assembly_tow/test_moored.py | 3 - .../test_scour_protection.py | 5 - tests/phases/install/test_install_phase.py | 3 - .../turbine_install/test_turbine_install.py | 12 - .../turbine_install/test_turbine_tasks.py | 3 - tests/phases/test_base.py | 5 - tests/test_config_management.py | 3 - .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 +-- versioneer.py | 298 +++++++++++------- 85 files changed, 624 insertions(+), 714 deletions(-) diff --git a/LICENSE b/LICENSE index dbb692d8..1c0c15ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index fa1e63bc..f03f6681 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,4 +1,3 @@ - # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -10,11 +9,11 @@ """Git implementation of _version.py.""" -import errno import os import re -import subprocess import sys +import errno +import subprocess def get_keywords(): @@ -58,17 +57,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -76,10 +78,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -116,16 +121,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -181,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -190,7 +201,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -198,19 +209,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -225,8 +243,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -234,10 +253,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -260,17 +288,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -279,10 +308,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -293,13 +324,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -330,8 +363,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -445,11 +477,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -469,9 +503,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } def get_versions(): @@ -485,8 +523,9 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) + return git_versions_from_keywords( + get_keywords(), cfg.tag_prefix, verbose + ) except NotThisMethod: pass @@ -495,13 +534,16 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): + for i in cfg.versionfile_source.split("/"): root = os.path.dirname(root) except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None, + } try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -515,6 +557,10 @@ def get_versions(): except NotThisMethod: pass - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 8320e99c..63fd1460 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,7 +7,6 @@ import openmdao.api as om - from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 4a50732d..5a416b43 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,7 +8,6 @@ import yaml from yaml import Dumper - from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index d02ab03f..0f618b4e 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,7 +6,6 @@ class Cargo(Object): - def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index e4e3792c..dec26889 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,7 +6,6 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 7df591ec..1cc75bae 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,7 +8,6 @@ import os import yaml - from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index 4654ec13..bade7d84 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,7 +88,6 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): - if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -139,7 +138,6 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): - if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index 8d7d0ca4..ec9fa5d6 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,7 +31,6 @@ def __init__(self, vessel, component): ) def __str__(self): - return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index 6f771cc0..c8217b15 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper - from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") + # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index b27a3e78..daa4a707 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -149,7 +148,6 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: - if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -262,16 +260,13 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: - if proposed_deck_space > vessel.storage.max_deck_space: - msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: - msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -332,7 +327,6 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: - vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index dbfc152a..c24ccfa6 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,7 +7,6 @@ import simpy - from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 0f2f3e1a..6f271c9b 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,7 +41,6 @@ def __init__( @process def start(self): - n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index 88c823a4..c952e905 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,7 +15,6 @@ WindowNotFound, AgentNotRegistered, ) - from ORBIT.core.components import ( Crane, JackingSys, @@ -86,7 +85,6 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): - duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 6aeb5ba1..ccb0a47d 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,10 +14,9 @@ from itertools import product import numpy as np +import ORBIT import pandas as pd from benedict import benedict - -import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -167,14 +166,12 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): - try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): - idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -205,7 +202,9 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -229,7 +228,9 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -453,7 +454,6 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): - if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,7 +500,6 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): - ret = {} for k, t in self.phase_times.items(): try: @@ -693,7 +692,6 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): - _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -727,7 +725,6 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: - phases = {**phases, **skipped} if not phases: break @@ -826,7 +823,6 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): - if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1104,7 +1100,6 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): - unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1140,7 +1135,6 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): - start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 6895400c..634b842c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,8 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from benedict import benedict - from ORBIT import ProjectManager +from benedict import benedict class ParametricManager: @@ -202,7 +201,6 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): - split = v.split("[") attr = split[0] @@ -298,7 +296,6 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): - if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 2e9b539d..1b39d91a 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,7 +10,6 @@ from copy import deepcopy from benedict import benedict - from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -70,7 +69,6 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): - if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 27343a58..1b93d209 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,7 +11,6 @@ import numpy as np from scipy.optimize import fsolve - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -333,7 +332,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index be00adbb..c109a7fa 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,7 +12,6 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt - from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.phases.design._cables import Plant, CableSystem @@ -567,7 +566,6 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): - ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -795,7 +793,6 @@ def create_project_csv(self, save_name): export_library_specs("cables", save_name, rows, file_ext="csv") def _format_windfarm_data(self): - # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1039,7 +1036,6 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): - self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index 6c6ae0a0..bf7af015 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,7 +6,6 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np - from ORBIT.phases.design._cables import CableSystem @@ -213,7 +212,6 @@ def design_result(self): } for name, cable in self.cables.items(): - output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index ab1e5349..082b3a9c 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,7 +9,6 @@ from math import pi, log from scipy.optimize import fsolve - from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -230,7 +229,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp ** 2, + "deck_space": D_tp**2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -355,7 +354,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -560,7 +559,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 383a4924..0dcf67d8 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index 1a2fe071..ea72c993 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,7 +7,6 @@ import numpy as np - from ORBIT.phases.design import DesignPhase @@ -284,7 +283,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass ** 0.5574 + substructure_pile_mass = 8 * substructure_mass**0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index efa66b4f..d36b91eb 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,7 +8,6 @@ from math import ceil import numpy as np - from ORBIT.phases.design import DesignPhase @@ -115,7 +114,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 58404a29..7bb34217 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 + mass = -0.153 * rating**2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index 224c4a5e..c8b0862e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,7 +7,6 @@ from numpy import exp, log - from ORBIT.phases.design import DesignPhase @@ -72,7 +71,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -113,7 +112,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -138,7 +137,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index d4d8a181..21120126 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,7 +10,6 @@ import numpy as np from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -237,7 +236,6 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: - try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -269,7 +267,6 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: - try: length, num_sections, *extra = sections.pop(0) if extra: @@ -291,12 +288,10 @@ def install_array_cables( break for _ in range(num_sections): - try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: - yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index f2481138..fa0833f2 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 486bc9e7..55bf7d32 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,7 +10,6 @@ from math import ceil from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -183,7 +182,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 + onshore_misc_cost = 11795 * capacity**0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index 97b93c3b..c4d159d6 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,7 +12,6 @@ import numpy as np import simpy import pandas as pd - from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 4312bfcf..5cd9feb2 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,7 +5,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 2f8f0c55..10391d6e 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,7 +7,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -111,9 +110,7 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ - - """ + """ """ jacket = Jacket(**self.config["jacket"]) @@ -132,7 +129,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): - items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -373,7 +369,6 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -438,9 +433,7 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index 04af017a..ee1fcb74 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,7 +7,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -340,7 +339,6 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 5a204709..02c7c259 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,7 +9,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -106,9 +105,7 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ - - """ + """ """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -119,7 +116,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): - delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -346,7 +342,6 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -408,9 +403,7 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index 3b3573b9..c4175f28 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -161,9 +160,7 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: - system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f90128ac..f1c5527b 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -139,7 +138,6 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index 6580e19a..a293363d 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,11 +6,10 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, process, le -from marmot._exceptions import AgentNotRegistered - +from marmot import Agent, le, process from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite +from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -144,7 +143,6 @@ def initialize_installation_vessel(self): @property def detailed_output(self): - return {} @@ -175,7 +173,6 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): - start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -196,7 +193,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range (3): + for _ in range(3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 04038af9..15bcbd79 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,7 +8,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -230,9 +229,7 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index 4cbd97f6..a02a3547 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -293,7 +292,6 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -357,7 +355,6 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index c38908b2..8376b274 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,7 +291,6 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -366,7 +364,6 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index 9dd3ee9a..db1c8ce6 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,7 +10,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index 057ff1bd..f65aa7a3 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index d23515a1..58e273ab 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,7 +12,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -321,7 +320,6 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -407,9 +405,7 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index b17e2ae8..8290eae7 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,71 +5,47 @@ from copy import deepcopy -from benedict import benedict -from ORBIT import ProjectManager - +from ORBIT import ProjectManager +from benedict import benedict DEFAULT_MULTIPLIERS = { - "blades": { - "domestic": .026, - "imported": .30 - }, - "nacelle": { - "domestic": .025, - "imported": .10 - }, - "tower": { - "domestic": .04, - "imported": .20, - "tariffs": .25, - }, - "monopile": { - "domestic": .085, - "imported": .28, - "tariffs": .25, - }, - "transition_piece": { - "domestic": .169, - "imported": .17, - "tariffs": .25, - }, - "array_cable": { - "domestic": .19, - "imported": 0. - }, - "export_cable": { - "domestic": .231, - "imported": 0. - }, - "oss_topside": { - "domestic": 0., - "imported": 0. - }, - "oss_substructure": { - "domestic": 0., - "imported": 0. - }, - } - - -TURBINE_CAPEX_SPLIT = { - "blades": 0.135, - "nacelle": 0.274, - "tower": 0.162 + "blades": {"domestic": 0.026, "imported": 0.30}, + "nacelle": {"domestic": 0.025, "imported": 0.10}, + "tower": { + "domestic": 0.04, + "imported": 0.20, + "tariffs": 0.25, + }, + "monopile": { + "domestic": 0.085, + "imported": 0.28, + "tariffs": 0.25, + }, + "transition_piece": { + "domestic": 0.169, + "imported": 0.17, + "tariffs": 0.25, + }, + "array_cable": {"domestic": 0.19, "imported": 0.0}, + "export_cable": {"domestic": 0.231, "imported": 0.0}, + "oss_topside": {"domestic": 0.0, "imported": 0.0}, + "oss_substructure": {"domestic": 0.0, "imported": 0.0}, } +TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} + + LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5 + "oss_topside": 0.5, } class SupplyChainManager: - def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -111,17 +87,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config['plant']) + plant = deepcopy(config["plant"]) # Run ProjectManager without install phases to generate design results - install_phases = config['install_phases'] - config['install_phases'] = [] + install_phases = config["install_phases"] + config["install_phases"] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config['plant'] = plant + config["plant"] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -130,8 +106,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config['install_phases'] = install_phases - config['design_phases'] = [] + config["install_phases"] = install_phases + config["design_phases"] = [] return config @@ -154,45 +130,51 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config['blades'] - nacelle_scenario = self.sc_config['nacelle'] - tower_scenario = self.sc_config['blades'] + blade_scenario = self.sc_config["blades"] + nacelle_scenario = self.sc_config["nacelle"] + tower_scenario = self.sc_config["blades"] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") - blade_mult = 0. + print( + f"Warning: scenario '{blade_scenario}' not found for category 'blades'." + ) + blade_mult = 0.0 nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") - nacelle_mult = 0. + print( + f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." + ) + nacelle_mult = 0.0 - raw_cost = config.get('project_parameters.turbine_capex', 1300) - blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult - nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult + raw_cost = config.get("project_parameters.turbine_capex", 1300) + blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult + nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = raw_cost * self.turbine_split['tower'] *\ - (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] + tower_tariffs = ( + raw_cost + * self.turbine_split["tower"] + * (1 - self.labor_split["tower"]) + * self.multipliers["tower"]["tariffs"] + ) else: - tower_tariffs = 0. + tower_tariffs = 0.0 tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") - tower_mult = 0. + print( + f"Warning: scenario '{tower_scenario}' not found for category 'tower'." + ) + tower_mult = 0.0 - tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult + tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult - config['project_parameters.turbine_capex'] = sum([ - raw_cost, - blade_adder, - nacelle_adder, - tower_adder, - tower_tariffs - ]) + config["project_parameters.turbine_capex"] = sum( + [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] + ) return config @@ -206,28 +188,29 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config['monopile.unit_cost'] - scenario = self.sc_config['monopile'] + raw_cost = config["monopile.unit_cost"] + scenario = self.sc_config["monopile"] if scenario == "domestic, imported steel": - adder = self.multipliers['monopile']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ - self.multipliers["monopile"]['tariffs'] + adder = self.multipliers["monopile"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["monopile"]) + * self.multipliers["monopile"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'monopile'." + ) + mult = 0.0 adder = raw_cost * mult - config['monopile.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -242,28 +225,29 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config['transition_piece.unit_cost'] - scenario = self.sc_config['transition_piece'] + raw_cost = config["transition_piece.unit_cost"] + scenario = self.sc_config["transition_piece"] if scenario == "domestic, imported steel": - adder = self.multipliers['transition_piece']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ - self.multipliers["transition_piece"]['tariffs'] + adder = self.multipliers["transition_piece"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["transition_piece"]) + * self.multipliers["transition_piece"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'transition_piece'." + ) + mult = 0.0 adder = raw_cost * mult - config['transition_piece.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -278,28 +262,31 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config['offshore_substation_topside.unit_cost'] - scenario = self.sc_config['oss_topside'] + raw_cost = config["offshore_substation_topside.unit_cost"] + scenario = self.sc_config["oss_topside"] if scenario == "domestic, imported steel": - adder = self.multipliers['oss_topside']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ - self.multipliers["oss_topside"]['tariffs'] + adder = self.multipliers["oss_topside"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["oss_topside"]) + * self.multipliers["oss_topside"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'oss_topside'." + ) + mult = 0.0 adder = raw_cost * mult - config['offshore_substation_topside.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["offshore_substation_topside.unit_cost"] = sum( + [raw_cost, adder, tariffs] + ) return config @@ -313,13 +300,15 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['array_cable'] + scenario = self.sc_config["array_cable"] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'array_cable'." + ) + mult = 0.0 - project.system_costs['ArrayCableInstallation'] *= (1 + mult) + project.system_costs["ArrayCableInstallation"] *= 1 + mult return project @@ -332,12 +321,14 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['export_cable'] + scenario = self.sc_config["export_cable"] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'export_cable'." + ) + mult = 0.0 - project.system_costs['ExportCableInstallation'] *= (1 + mult) + project.system_costs["ExportCableInstallation"] *= 1 + mult return project diff --git a/docs/Makefile b/docs/Makefile index 298ea9e2..51285967 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 38ceb207..555a6637 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -sys.path.insert(0, os.path.abspath("..")) - import ORBIT +sys.path.insert(0, os.path.abspath("..")) + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 50478a79..0a3683f9 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW \ No newline at end of file +turbine_rating: 15 # MW diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 75b6fd5c..00a13ba3 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,31 +1,40 @@ -import pandas as pd +import os import math + import numpy as np +import pandas as pd import matplotlib as mpl -import matplotlib.pyplot as plt import matplotlib.text as txt -import os +import matplotlib.pyplot as plt -def mysave(fig, froot, mode='png'): - assert mode in ['png', 'eps', 'pdf', 'all'] + +def mysave(fig, froot, mode="png"): + assert mode in ["png", "eps", "pdf", "all"] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: legs.append(a.get_legend()) + if not addLeg is None: + legs.append(a.get_legend()) ext = [] - if mode == 'png' or mode == 'all': - ext.append('png') - if mode == 'eps': # or mode == 'all': - ext.append('eps') - if mode == 'pdf' or mode == 'all': - ext.append('pdf') + if mode == "png" or mode == "all": + ext.append("png") + if mode == "eps": # or mode == 'all': + ext.append("eps") + if mode == "pdf" or mode == "all": + ext.append("pdf") for sfx in ext: - fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', - dpi=dpiVal, bbox_extra_artists=legs) + fig.savefig( + fileName + "." + sfx, + format=sfx, + pad_inches=padding, + bbox_inches="tight", + dpi=dpiVal, + bbox_extra_artists=legs, + ) titleSize = 24 # 40 #38 @@ -38,32 +47,48 @@ def mysave(fig, froot, mode='png'): linewidth = 3 -def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): - assert type(mode) == type('') - assert mode.lower() in ['save', 'show'], 'Unknown mode' - - def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): - if mode.lower() == 'show': +def myformat( + ax, + linewidth=linewidth, + xticklabel=tickLabelSize, + yticklabel=tickLabelSize, + mode="save", +): + assert type(mode) == type("") + assert mode.lower() in ["save", "show"], "Unknown mode" + + def myformat( + myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel + ): + if mode.lower() == "show": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): + t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_title( + myax.get_title(), size=titleSize + deltaShow, weight="bold" + ) + myax.set_xlabel( + myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" + ) + myax.set_ylabel( + myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" + ) myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -75,27 +100,29 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == 'save': + elif mode.lower() == "save": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize) + for t in leg.get_texts(): + t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') + myax.set_title(myax.get_title(), size=titleSize, weight="bold") + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -108,40 +135,62 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl i.set_linewidth(3) if type(ax) == type([]): - for i in ax: myformat(i) + for i in ax: + myformat(i) else: myformat(ax) + def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax + def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """ Waterfall plot comparing European andUS manufactining costs""" + """Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') + h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) - ax.set_ylabel('Capital Expenditures, $/kW') - ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') - - h[3].set_linestyle('--') + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) + ) + ax.set_ylabel("Capital Expenditures, $/kW") + ax.set_title( + "Comparison of different cost premiums between \nimported and domestically manufactured components" + ) + + h[3].set_linestyle("--") h[3].set_linewidth(1.75) - h[3].set_edgecolor('k') - - ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) - ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) - ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) + h[3].set_edgecolor("k") + + ax.text( + x[1], + 2000, + bar_text["transit"], + horizontalalignment="center", + ) + ax.text( + x[2], + 2000, + bar_text["factory"], + horizontalalignment="center", + ) + ax.text( + x[3], + 2000, + bar_text["margin"], + horizontalalignment="center", + ) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() + def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -150,40 +199,52 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k,v in y.items()]) + y_init = np.sum([v[0] for k, v in y.items()]) - for k,v in y.items(): - y1 = [yi+vi for yi, vi in zip(y0,v)] + for k, v in y.items(): + y1 = [yi + vi for yi, vi in zip(y0, v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, 'w') + ax.plot(x, y1 / y_init, "w") y0 = y1 # Define margin - ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') + ax.fill_between( + x, + y1 / y_init, + np.ones(len(x)), + color=color["Cost margin"], + label="Margin", + ) - final_margin = round( 100* (1 - y1[-1] / y_init), 1) + final_margin = round(100 * (1 - y1[-1] / y_init), 1) - y_margin = ((1 + y1[-1] / y_init) /2) + y_margin = (1 + y1[-1] / y_init) / 2 - margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' + margin_text = ( + " " + + str(final_margin) + + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" + ) right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], 'k') - ax.text(right_bound, y_margin, margin_text, verticalalignment='center') - ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], "k") + ax.text(right_bound, y_margin, margin_text, verticalalignment="center") + ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') - ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') + ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") + ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") - ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') + ax.set_ylabel( + "CapEx breakdown relative to \ncomponents imported from Europe, %" + ) if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index 2b1bdafe..eed5b2c9 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,12 +12,10 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')" + "optional_input": "unit, (optional, default: 'default')", } - output_config = { - "example_output": "unit" - } + output_config = {"example_output": "unit"} def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -45,9 +43,7 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return { - "example_detailed_output": self.result - } + return {"example_detailed_output": self.result} @property def total_cost(self): @@ -60,9 +56,7 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return { - "example_output": self.result - } + return {"example_output": self.result} # === Annotated Example === @@ -75,18 +69,21 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": {"depth": "m"}, # For common inputs that will be shared across many modules, - "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules - "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT - - - + "site": { + "depth": "m" + }, # For common inputs that will be shared across many modules, + "plant": { + "num_turbines": "int" + }, # it's best to look up how the variable is named in existing modules + "turbine": { + "turbine_rating": "MW" + }, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -97,8 +94,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -114,13 +111,18 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above - - - self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library( + config, **kwargs + ) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config( + config + ) # if it hasn't already been and validate the config against '.expected_config' from above + + self._design = self.config.get( + "spar_design", {} + ) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -152,7 +154,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -174,8 +176,10 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get( + "stiffened_column_CR", 3120 + ) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -194,7 +198,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -219,7 +223,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -267,7 +271,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index e15c8156..4cc5fa25 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,7 +11,6 @@ def test_wisdem_monopile_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -23,7 +22,6 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -35,7 +33,6 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index a480e04e..5579f62c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,6 @@ import pytest from marmot import Environment - from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -24,27 +23,23 @@ def pytest_configure(): @pytest.fixture() def env(): - return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): - specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): - specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): - specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -53,7 +48,6 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): - specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -62,19 +56,16 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): - specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): - return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): - yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index 0ce94758..b5f5208b 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,7 +8,6 @@ import pandas as pd import pytest from marmot import le - from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 7320a9f6..9cac3f50 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -58,7 +57,6 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): - project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 915af401..6415118d 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,7 +8,6 @@ import pytest from marmot import Environment - from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -19,7 +18,6 @@ def __init__(self): def test_port_creation(): - env = Environment() port = Port(env) item = SampleItem() @@ -32,7 +30,6 @@ def test_port_creation(): def test_get_item(): - env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index cd1ad5cd..39c42a82 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -209,7 +208,6 @@ def test_correct_turbines(): def test_floating_calculations(): - base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index e1cf3024..ce7a1cd5 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,7 +11,6 @@ import numpy as np import pytest - from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -111,7 +110,6 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): - c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index 9db78fed..dbe18324 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,7 +8,6 @@ from copy import deepcopy import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -104,7 +103,6 @@ def test_design_result(): def test_floating_length_calculations(): - base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 0762b46b..2f69ed18 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,7 +10,6 @@ from itertools import product import pytest - from ORBIT.phases.design import MonopileDesign base = { @@ -37,7 +36,6 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): - config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -61,7 +59,6 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): - test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -80,7 +77,6 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -93,7 +89,6 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): - test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -107,7 +102,6 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index 88a7a747..c59ef535 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT.phases.design import MooringSystemDesign base = { @@ -21,7 +20,6 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): - config = deepcopy(base) config["site"]["depth"] = depth @@ -34,7 +32,6 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): - config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -46,7 +43,6 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): - m = MooringSystemDesign(base) m.run() @@ -75,7 +71,6 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): - config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index b2dd6316..f17b3bd7 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -24,7 +23,6 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -51,7 +49,6 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): - test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -72,7 +69,6 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index 301e5894..d4168fd1 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 7c710fb9..30a134f3 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index 393cf7c1..dbc937c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SparDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index 5a01c14b..f9b1c9a9 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ArrayCableInstallation(config) assert sim.env @@ -37,7 +35,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -53,7 +50,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -72,7 +68,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,7 +84,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -114,7 +108,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): - sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -131,7 +124,6 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -163,7 +155,6 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): - base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -183,7 +174,6 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index 3ab42d15..f3d03350 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -28,7 +27,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -59,7 +57,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index 34669075..e837176c 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -42,7 +40,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -58,7 +55,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -77,7 +73,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -94,7 +89,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -119,7 +113,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -150,7 +143,6 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -182,7 +174,6 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -214,7 +205,6 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index 6811e631..c601a5c6 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = JacketInstallation(config, weather=weather) sim.run() @@ -97,7 +93,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): - base = JacketInstallation(config) base.run() @@ -116,7 +111,6 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): - base = JacketInstallation(config) base.run() @@ -134,7 +128,6 @@ def test_foundation_type(config): def test_kwargs_piles(): - sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -154,7 +147,6 @@ def test_kwargs_piles(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -176,7 +168,6 @@ def test_kwargs_piles(): def test_kwargs_suction(): - config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -197,7 +188,6 @@ def test_kwargs_suction(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 57538063..1759bc3e 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = MonopileInstallation(config, weather=weather) sim.run() @@ -92,7 +88,6 @@ def test_for_complete_logging(weather, config): def test_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -113,7 +108,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -145,7 +139,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -168,7 +161,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -203,7 +195,6 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index bff023f5..2fa11d9e 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -35,7 +34,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -55,7 +53,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 116f7558..3583bbda 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -61,7 +60,6 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): - new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -74,7 +72,6 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -103,7 +100,6 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): - base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -117,7 +113,6 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index be32be3d..30ed4475 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -45,7 +43,6 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): - sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -58,7 +55,6 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -82,7 +78,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -104,7 +99,6 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): - sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -118,7 +112,6 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): - sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -139,7 +132,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -171,7 +163,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -195,7 +186,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 67a28c40..758df489 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -25,7 +24,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -44,7 +42,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index 00fa2b4e..b9a08bac 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -28,7 +27,6 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): - _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -54,7 +52,6 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): - _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -92,7 +89,6 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): - num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index dafad84b..25d7db92 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index e1fc0af7..72619642 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index 85e372c7..ae1c9313 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -51,7 +50,6 @@ def test_full_run_logging(weather): def test_kwargs(): - sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -61,7 +59,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -83,7 +80,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -96,7 +92,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index 6b600eb2..cba9802c 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,7 +9,6 @@ import pandas as pd import pytest from marmot import Environment - from ORBIT.phases.install import InstallPhase @@ -45,7 +44,6 @@ def setup_simulation(self): def test_abstract_methods(): - with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -53,7 +51,6 @@ def test_abstract_methods(): def test_run(): - sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index aac2de9f..0592999a 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): - sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -56,7 +54,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): - sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -80,7 +77,6 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): - sim = TurbineInstallation(config) assert sim.wtiv @@ -97,7 +93,6 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = TurbineInstallation(config, weather=weather) sim.run() @@ -120,7 +115,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): - sim = TurbineInstallation(config) sim.run() @@ -131,7 +125,6 @@ def test_for_complete_installation(config): def test_kwargs(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -153,7 +146,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -175,7 +167,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -200,7 +191,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} @@ -225,7 +215,6 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -245,7 +234,6 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): - vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 055da73d..2042f639 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -33,7 +32,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -56,7 +54,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 209983ac..01e37b7b 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,14 +18,12 @@ def test_good_config(): - config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): - config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -33,7 +31,6 @@ def test_missing_key(): def test_optional(): - config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -41,7 +38,6 @@ def test_optional(): def test_variable_key(): - config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -50,7 +46,6 @@ def test_variable_key(): def test_optional_dict(): - config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index f635f271..ffd84920 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,7 +7,6 @@ import os import pytest - from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -15,7 +14,6 @@ def test_save_and_load_equality(tmp_yaml_del): - save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -23,7 +21,6 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): - config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 059202fb..656db0d8 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,9 +6,8 @@ from copy import deepcopy -from numpy.testing import assert_almost_equal - from ORBIT import ProjectManager +from numpy.testing import assert_almost_equal from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -16,7 +15,6 @@ def test_fixed_phase_cost_passing(): - project = ProjectManager(fixed) project.run() @@ -47,7 +45,6 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): - project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 4d73da75..5d33cfca 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,9 +7,8 @@ import pandas as pd import pytest -from benedict import benedict - from ORBIT import ProjectManager, ParametricManager +from benedict import benedict from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -24,7 +23,6 @@ def test_for_equal_results(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -37,7 +35,6 @@ def test_for_equal_results(): def test_weather(): - without = ParametricManager(complete_project, params, funcs) without.run() @@ -50,7 +47,6 @@ def test_weather(): def test_individual_phase(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -67,7 +63,6 @@ def test_individual_phase(): def test_bad_result_attribute(): - funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -79,7 +74,6 @@ def test_bad_result_attribute(): def test_bad_result_structure(): - funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -91,7 +85,6 @@ def test_bad_result_structure(): def test_product_option(): - params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 7e62a225..9cbf9ad3 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,10 +8,9 @@ import pandas as pd import pytest - from ORBIT import ProjectManager -from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather +from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -26,10 +25,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") + ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): - project = ProjectManager(config, weather=weather) project.run() @@ -47,11 +46,9 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: - assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: - assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -130,7 +127,6 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: - i, expected = test response = TestProjectManager.find_key_match(i) @@ -143,13 +139,11 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: - assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): - config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -169,7 +163,6 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): - config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -233,7 +226,6 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): - config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -283,7 +275,6 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): - # Not a subclass class CustomInstallPhase: pass @@ -305,7 +296,6 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) - # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -318,11 +308,13 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase + assert ( + ProjectManager.find_key_match("CustomInstallPhase") + == CustomInstallPhase + ) def test_custom_design_phases(): - # Not a subclass class CustomDesignPhase: pass @@ -344,7 +336,6 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) - # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -357,11 +348,13 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + assert ( + ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + ) + ### Design Phase Interactions def test_design_phases(): - config_with_design = deepcopy(config) # Add MonopileDesign @@ -386,7 +379,6 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): - # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -467,7 +459,6 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): - incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -477,7 +468,6 @@ def test_incomplete_config(): def test_wrong_phases(): - wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -487,7 +477,6 @@ def test_wrong_phases(): def test_bad_dates(): - bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -500,7 +489,6 @@ def test_bad_dates(): def test_no_defined_start(): - missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -513,7 +501,6 @@ def test_no_defined_start(): def test_circular_dependencies(): - circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -532,7 +519,6 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): - wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -552,7 +538,6 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): - data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -592,7 +577,6 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): - project = ProjectManager(config) project.run() @@ -607,7 +591,6 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): - project = ProjectManager(complete_project) project.run() @@ -633,7 +616,6 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -649,7 +631,6 @@ def test_monthly_expenses(): def test_monthly_revenue(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -666,7 +647,6 @@ def test_monthly_revenue(): def test_cash_flow(): - project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -684,7 +664,6 @@ def test_cash_flow(): def test_npv(): - project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -721,7 +700,6 @@ def test_npv(): def test_soft_costs(): - project = ProjectManager(complete_project) baseline = project.soft_capex @@ -757,7 +735,6 @@ def test_soft_costs(): def test_project_costs(): - project = ProjectManager(complete_project) baseline = project.project_capex @@ -783,7 +760,6 @@ def test_project_costs(): def test_capex_categories(): - project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 64fea1c8..96361d2f 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,4 +1,3 @@ - # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -277,16 +276,18 @@ """ from __future__ import print_function + +import os +import re +import sys +import json +import errno +import subprocess + try: import configparser except ImportError: import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys class VersioneerConfig: @@ -308,11 +309,13 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") + err = ( + "Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND')." + ) raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -325,8 +328,10 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) + print( + "Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py) + ) except NameError: pass return root @@ -348,6 +353,7 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None + cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -372,17 +378,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -390,10 +399,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -418,7 +430,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return stdout, p.returncode -LONG_VERSION_PY['git'] = ''' +LONG_VERSION_PY[ + "git" +] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -993,7 +1007,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1002,7 +1016,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1010,19 +1024,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1037,8 +1058,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1046,10 +1068,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1072,17 +1103,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -1091,10 +1123,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1105,13 +1139,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1167,16 +1203,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1205,11 +1247,17 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1218,8 +1266,9 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps( + versions, sort_keys=True, indent=1, separators=(",", ": ") + ) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1251,8 +1300,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1366,11 +1414,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -1390,9 +1440,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } class VersioneerBadRootError(Exception): @@ -1415,8 +1469,9 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" + assert ( + cfg.versionfile_source is not None + ), "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1470,9 +1525,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } def get_version(): @@ -1521,6 +1580,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1553,14 +1613,17 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join( + self.build_lib, cfg.versionfile_build + ) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1581,17 +1644,21 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if 'py2exe' in sys.modules: # py2exe enabled? + if "py2exe" in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1610,13 +1677,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1643,8 +1714,10 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file( + target_versionfile, self._versioneer_generated_versions + ) + cmds["sdist"] = cmd_sdist return cmds @@ -1699,11 +1772,15 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except ( + EnvironmentError, + configparser.NoSectionError, + configparser.NoOptionError, + ) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print( + "Adding sample versioneer config to setup.cfg", file=sys.stderr + ) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1712,15 +1789,18 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1762,8 +1842,10 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print( + " appending versionfile_source ('%s') to MANIFEST.in" + % cfg.versionfile_source + ) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From 22b2c408beee47eb0a669b12f93b2535be92dc9e Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Thu, 23 Feb 2023 10:58:49 -0700 Subject: [PATCH 07/19] add ability to layout data to project/plant with default of cables/ --- ORBIT/phases/design/array_system_design.py | 29 ++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 5f349ed1..6fbf911d 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -14,6 +14,7 @@ import matplotlib.pyplot as plt from ORBIT.core.library import export_library_specs, extract_library_specs +from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -363,7 +364,7 @@ def run(self): self._create_wind_farm_layout() self._create_cable_section_lengths() - def save_layout(self, save_name, return_df=False): + def save_layout(self, save_name, return_df=False, folder="cables"): """Outputs a csv of the substation and turbine positional and cable related components. @@ -375,12 +376,23 @@ def save_layout(self, save_name, return_df=False): return_df : bool, optional If true, returns layout_df, a pandas.DataFrame of the cabling layout, by default False. + folder : str, optional + If "cables", then the layout will saved to the "cables" folder, and + if "plant", then the layout will be saved to the "project/plant" folder. Returns ------- pd.DataFrame The DataFrame with the layout data. + + Raises + ------ + ValueError + Raised if ``folder`` is not one of "cables" or "plant". """ + if folder not in ("cables", "plant"): + raise ValueError("`folder` must be one of: 'cables' or plant'.") + num_turbines = self.system.num_turbines columns = [ "id", @@ -448,7 +460,7 @@ def save_layout(self, save_name, return_df=False): print( f"Saving custom array CSV to: /cables/{save_name}.csv" ) - export_library_specs("cables", save_name, data, file_ext="csv") + export_library_specs(folder, save_name, data, file_ext="csv") if return_df: return layout_df @@ -725,14 +737,21 @@ def __init__(self, config, distance=False, **kwargs): super().__init__(config, **kwargs) self.distance = config["array_system_design"].get("distance", distance) - def create_project_csv(self, save_name): + def create_project_csv(self, save_name, folder="cables"): """Creates a base CSV in <`library_path`>/cables/ Parameters ---------- save_name : [type] [description] + + Raises + ------ + ValueError + Raised if ``folder`` is not one of "cables" or "plant". """ + if folder not in ("cables", "plant"): + raise ValueError("`folder` must be one of: 'cables' or plant'.") self._initialize_cables() self.create_strings() @@ -792,7 +811,7 @@ def create_project_csv(self, save_name): print( f"Saving custom array CSV to: /cables/{save_name}.csv" ) - export_library_specs("cables", save_name, rows, file_ext="csv") + export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): @@ -849,7 +868,7 @@ def _initialize_custom_data(self): ) except LibraryItemNotFoundError: self.location_data = extract_library_specs( - "project/plant", windfarm, file_type="csv" + "plant", windfarm, file_type="csv" ) # Make sure no data is missing missing = set(self.COLUMNS).difference(self.location_data.columns) From 0d3baeaa892147f24ac41f2eb61aa0ef97507a30 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 18:14:45 +0000 Subject: [PATCH 08/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++++---- ORBIT/api/wisdem.py | 1 - ORBIT/config.py | 1 - ORBIT/core/cargo.py | 1 - ORBIT/core/components.py | 1 - ORBIT/core/defaults/__init__.py | 1 - ORBIT/core/environment.py | 2 - ORBIT/core/exceptions.py | 1 - ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 - ORBIT/core/port.py | 1 - ORBIT/core/supply_chain.py | 1 - ORBIT/core/vessel.py | 2 - ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 - ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 8 +- ORBIT/phases/design/export_system_design.py | 2 - ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 - ORBIT/phases/install/cable_install/common.py | 1 - ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 - ORBIT/phases/install/jacket_install/common.py | 1 - .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 - .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 - ORBIT/phases/install/oss_install/common.py | 2 - ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 - .../quayside_assembly_tow/gravity_base.py | 3 - .../install/quayside_assembly_tow/moored.py | 3 - .../scour_protection_install/standard.py | 1 - .../phases/install/turbine_install/common.py | 1 - .../install/turbine_install/standard.py | 4 - ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 +++++++---- templates/design_module.py | 74 +++-- tests/api/test_wisdem_api.py | 3 - tests/conftest.py | 9 - tests/core/test_environment.py | 1 - tests/core/test_library.py | 2 - tests/core/test_port.py | 3 - .../phases/design/test_array_system_design.py | 2 - tests/phases/design/test_cable.py | 2 - .../design/test_export_system_design.py | 2 - tests/phases/design/test_monopile_design.py | 6 - .../design/test_mooring_system_design.py | 5 - tests/phases/design/test_oss_design.py | 4 - .../design/test_scour_protection_design.py | 1 - .../design/test_semisubmersible_design.py | 4 - tests/phases/design/test_spar_design.py | 4 - .../cable_install/test_array_install.py | 10 - .../install/cable_install/test_cable_tasks.py | 3 - .../cable_install/test_export_install.py | 10 - .../jacket_install/test_jacket_install.py | 10 - .../monopile_install/test_monopile_install.py | 9 - .../monopile_install/test_monopile_tasks.py | 3 - .../mooring_install/test_mooring_install.py | 5 - .../install/oss_install/test_oss_install.py | 10 - .../install/oss_install/test_oss_tasks.py | 3 - .../quayside_assembly_tow/test_common.py | 4 - .../test_gravity_based.py | 3 - .../quayside_assembly_tow/test_moored.py | 3 - .../test_scour_protection.py | 5 - tests/phases/install/test_install_phase.py | 3 - .../turbine_install/test_turbine_install.py | 12 - .../turbine_install/test_turbine_tasks.py | 3 - tests/phases/test_base.py | 5 - tests/test_config_management.py | 3 - .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 +-- versioneer.py | 298 +++++++++++------- 85 files changed, 626 insertions(+), 716 deletions(-) diff --git a/LICENSE b/LICENSE index dbb692d8..1c0c15ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index fa1e63bc..f03f6681 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,4 +1,3 @@ - # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -10,11 +9,11 @@ """Git implementation of _version.py.""" -import errno import os import re -import subprocess import sys +import errno +import subprocess def get_keywords(): @@ -58,17 +57,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -76,10 +78,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -116,16 +121,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -181,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -190,7 +201,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -198,19 +209,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -225,8 +243,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -234,10 +253,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -260,17 +288,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -279,10 +308,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -293,13 +324,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -330,8 +363,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -445,11 +477,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -469,9 +503,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } def get_versions(): @@ -485,8 +523,9 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) + return git_versions_from_keywords( + get_keywords(), cfg.tag_prefix, verbose + ) except NotThisMethod: pass @@ -495,13 +534,16 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): + for i in cfg.versionfile_source.split("/"): root = os.path.dirname(root) except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None, + } try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -515,6 +557,10 @@ def get_versions(): except NotThisMethod: pass - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 8320e99c..63fd1460 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,7 +7,6 @@ import openmdao.api as om - from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 4a50732d..5a416b43 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,7 +8,6 @@ import yaml from yaml import Dumper - from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index d02ab03f..0f618b4e 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,7 +6,6 @@ class Cargo(Object): - def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index e4e3792c..dec26889 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,7 +6,6 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 7df591ec..1cc75bae 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,7 +8,6 @@ import os import yaml - from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index 4654ec13..bade7d84 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,7 +88,6 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): - if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -139,7 +138,6 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): - if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index 8d7d0ca4..ec9fa5d6 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,7 +31,6 @@ def __init__(self, vessel, component): ) def __str__(self): - return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index 6f771cc0..c8217b15 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper - from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") + # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index b27a3e78..daa4a707 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -149,7 +148,6 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: - if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -262,16 +260,13 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: - if proposed_deck_space > vessel.storage.max_deck_space: - msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: - msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -332,7 +327,6 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: - vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index dbfc152a..c24ccfa6 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,7 +7,6 @@ import simpy - from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 0f2f3e1a..6f271c9b 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,7 +41,6 @@ def __init__( @process def start(self): - n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index 88c823a4..c952e905 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,7 +15,6 @@ WindowNotFound, AgentNotRegistered, ) - from ORBIT.core.components import ( Crane, JackingSys, @@ -86,7 +85,6 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): - duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 6aeb5ba1..ccb0a47d 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,10 +14,9 @@ from itertools import product import numpy as np +import ORBIT import pandas as pd from benedict import benedict - -import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -167,14 +166,12 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): - try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): - idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -205,7 +202,9 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -229,7 +228,9 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -453,7 +454,6 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): - if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,7 +500,6 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): - ret = {} for k, t in self.phase_times.items(): try: @@ -693,7 +692,6 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): - _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -727,7 +725,6 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: - phases = {**phases, **skipped} if not phases: break @@ -826,7 +823,6 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): - if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1104,7 +1100,6 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): - unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1140,7 +1135,6 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): - start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 6895400c..634b842c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,8 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from benedict import benedict - from ORBIT import ProjectManager +from benedict import benedict class ParametricManager: @@ -202,7 +201,6 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): - split = v.split("[") attr = split[0] @@ -298,7 +296,6 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): - if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 2e9b539d..1b39d91a 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,7 +10,6 @@ from copy import deepcopy from benedict import benedict - from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -70,7 +69,6 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): - if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 27343a58..1b93d209 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,7 +11,6 @@ import numpy as np from scipy.optimize import fsolve - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -333,7 +332,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 6fbf911d..28b780d9 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,7 +12,6 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt - from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -384,7 +383,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -579,7 +578,6 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): - ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -744,7 +742,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError @@ -814,7 +812,6 @@ def create_project_csv(self, save_name, folder="cables"): export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): - # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1062,7 +1059,6 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): - self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index 6c6ae0a0..bf7af015 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,7 +6,6 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np - from ORBIT.phases.design._cables import CableSystem @@ -213,7 +212,6 @@ def design_result(self): } for name, cable in self.cables.items(): - output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index ab1e5349..082b3a9c 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,7 +9,6 @@ from math import pi, log from scipy.optimize import fsolve - from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -230,7 +229,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp ** 2, + "deck_space": D_tp**2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -355,7 +354,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -560,7 +559,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 383a4924..0dcf67d8 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index 1a2fe071..ea72c993 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,7 +7,6 @@ import numpy as np - from ORBIT.phases.design import DesignPhase @@ -284,7 +283,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass ** 0.5574 + substructure_pile_mass = 8 * substructure_mass**0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index efa66b4f..d36b91eb 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,7 +8,6 @@ from math import ceil import numpy as np - from ORBIT.phases.design import DesignPhase @@ -115,7 +114,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 58404a29..7bb34217 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 + mass = -0.153 * rating**2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index 224c4a5e..c8b0862e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,7 +7,6 @@ from numpy import exp, log - from ORBIT.phases.design import DesignPhase @@ -72,7 +71,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -113,7 +112,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -138,7 +137,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index d4d8a181..21120126 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,7 +10,6 @@ import numpy as np from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -237,7 +236,6 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: - try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -269,7 +267,6 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: - try: length, num_sections, *extra = sections.pop(0) if extra: @@ -291,12 +288,10 @@ def install_array_cables( break for _ in range(num_sections): - try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: - yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index f2481138..fa0833f2 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 486bc9e7..55bf7d32 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,7 +10,6 @@ from math import ceil from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -183,7 +182,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 + onshore_misc_cost = 11795 * capacity**0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index 97b93c3b..c4d159d6 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,7 +12,6 @@ import numpy as np import simpy import pandas as pd - from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 4312bfcf..5cd9feb2 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,7 +5,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 2f8f0c55..10391d6e 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,7 +7,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -111,9 +110,7 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ - - """ + """ """ jacket = Jacket(**self.config["jacket"]) @@ -132,7 +129,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): - items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -373,7 +369,6 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -438,9 +433,7 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index 04af017a..ee1fcb74 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,7 +7,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -340,7 +339,6 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 5a204709..02c7c259 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,7 +9,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -106,9 +105,7 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ - - """ + """ """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -119,7 +116,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): - delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -346,7 +342,6 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -408,9 +403,7 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index 3b3573b9..c4175f28 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -161,9 +160,7 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: - system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f90128ac..f1c5527b 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -139,7 +138,6 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index 6580e19a..a293363d 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,11 +6,10 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, process, le -from marmot._exceptions import AgentNotRegistered - +from marmot import Agent, le, process from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite +from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -144,7 +143,6 @@ def initialize_installation_vessel(self): @property def detailed_output(self): - return {} @@ -175,7 +173,6 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): - start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -196,7 +193,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range (3): + for _ in range(3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 04038af9..15bcbd79 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,7 +8,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -230,9 +229,7 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index 4cbd97f6..a02a3547 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -293,7 +292,6 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -357,7 +355,6 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index c38908b2..8376b274 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,7 +291,6 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -366,7 +364,6 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index 9dd3ee9a..db1c8ce6 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,7 +10,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index 057ff1bd..f65aa7a3 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index d23515a1..58e273ab 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,7 +12,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -321,7 +320,6 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -407,9 +405,7 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index b17e2ae8..8290eae7 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,71 +5,47 @@ from copy import deepcopy -from benedict import benedict -from ORBIT import ProjectManager - +from ORBIT import ProjectManager +from benedict import benedict DEFAULT_MULTIPLIERS = { - "blades": { - "domestic": .026, - "imported": .30 - }, - "nacelle": { - "domestic": .025, - "imported": .10 - }, - "tower": { - "domestic": .04, - "imported": .20, - "tariffs": .25, - }, - "monopile": { - "domestic": .085, - "imported": .28, - "tariffs": .25, - }, - "transition_piece": { - "domestic": .169, - "imported": .17, - "tariffs": .25, - }, - "array_cable": { - "domestic": .19, - "imported": 0. - }, - "export_cable": { - "domestic": .231, - "imported": 0. - }, - "oss_topside": { - "domestic": 0., - "imported": 0. - }, - "oss_substructure": { - "domestic": 0., - "imported": 0. - }, - } - - -TURBINE_CAPEX_SPLIT = { - "blades": 0.135, - "nacelle": 0.274, - "tower": 0.162 + "blades": {"domestic": 0.026, "imported": 0.30}, + "nacelle": {"domestic": 0.025, "imported": 0.10}, + "tower": { + "domestic": 0.04, + "imported": 0.20, + "tariffs": 0.25, + }, + "monopile": { + "domestic": 0.085, + "imported": 0.28, + "tariffs": 0.25, + }, + "transition_piece": { + "domestic": 0.169, + "imported": 0.17, + "tariffs": 0.25, + }, + "array_cable": {"domestic": 0.19, "imported": 0.0}, + "export_cable": {"domestic": 0.231, "imported": 0.0}, + "oss_topside": {"domestic": 0.0, "imported": 0.0}, + "oss_substructure": {"domestic": 0.0, "imported": 0.0}, } +TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} + + LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5 + "oss_topside": 0.5, } class SupplyChainManager: - def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -111,17 +87,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config['plant']) + plant = deepcopy(config["plant"]) # Run ProjectManager without install phases to generate design results - install_phases = config['install_phases'] - config['install_phases'] = [] + install_phases = config["install_phases"] + config["install_phases"] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config['plant'] = plant + config["plant"] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -130,8 +106,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config['install_phases'] = install_phases - config['design_phases'] = [] + config["install_phases"] = install_phases + config["design_phases"] = [] return config @@ -154,45 +130,51 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config['blades'] - nacelle_scenario = self.sc_config['nacelle'] - tower_scenario = self.sc_config['blades'] + blade_scenario = self.sc_config["blades"] + nacelle_scenario = self.sc_config["nacelle"] + tower_scenario = self.sc_config["blades"] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") - blade_mult = 0. + print( + f"Warning: scenario '{blade_scenario}' not found for category 'blades'." + ) + blade_mult = 0.0 nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") - nacelle_mult = 0. + print( + f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." + ) + nacelle_mult = 0.0 - raw_cost = config.get('project_parameters.turbine_capex', 1300) - blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult - nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult + raw_cost = config.get("project_parameters.turbine_capex", 1300) + blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult + nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = raw_cost * self.turbine_split['tower'] *\ - (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] + tower_tariffs = ( + raw_cost + * self.turbine_split["tower"] + * (1 - self.labor_split["tower"]) + * self.multipliers["tower"]["tariffs"] + ) else: - tower_tariffs = 0. + tower_tariffs = 0.0 tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") - tower_mult = 0. + print( + f"Warning: scenario '{tower_scenario}' not found for category 'tower'." + ) + tower_mult = 0.0 - tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult + tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult - config['project_parameters.turbine_capex'] = sum([ - raw_cost, - blade_adder, - nacelle_adder, - tower_adder, - tower_tariffs - ]) + config["project_parameters.turbine_capex"] = sum( + [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] + ) return config @@ -206,28 +188,29 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config['monopile.unit_cost'] - scenario = self.sc_config['monopile'] + raw_cost = config["monopile.unit_cost"] + scenario = self.sc_config["monopile"] if scenario == "domestic, imported steel": - adder = self.multipliers['monopile']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ - self.multipliers["monopile"]['tariffs'] + adder = self.multipliers["monopile"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["monopile"]) + * self.multipliers["monopile"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'monopile'." + ) + mult = 0.0 adder = raw_cost * mult - config['monopile.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -242,28 +225,29 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config['transition_piece.unit_cost'] - scenario = self.sc_config['transition_piece'] + raw_cost = config["transition_piece.unit_cost"] + scenario = self.sc_config["transition_piece"] if scenario == "domestic, imported steel": - adder = self.multipliers['transition_piece']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ - self.multipliers["transition_piece"]['tariffs'] + adder = self.multipliers["transition_piece"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["transition_piece"]) + * self.multipliers["transition_piece"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'transition_piece'." + ) + mult = 0.0 adder = raw_cost * mult - config['transition_piece.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -278,28 +262,31 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config['offshore_substation_topside.unit_cost'] - scenario = self.sc_config['oss_topside'] + raw_cost = config["offshore_substation_topside.unit_cost"] + scenario = self.sc_config["oss_topside"] if scenario == "domestic, imported steel": - adder = self.multipliers['oss_topside']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ - self.multipliers["oss_topside"]['tariffs'] + adder = self.multipliers["oss_topside"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["oss_topside"]) + * self.multipliers["oss_topside"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'oss_topside'." + ) + mult = 0.0 adder = raw_cost * mult - config['offshore_substation_topside.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["offshore_substation_topside.unit_cost"] = sum( + [raw_cost, adder, tariffs] + ) return config @@ -313,13 +300,15 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['array_cable'] + scenario = self.sc_config["array_cable"] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'array_cable'." + ) + mult = 0.0 - project.system_costs['ArrayCableInstallation'] *= (1 + mult) + project.system_costs["ArrayCableInstallation"] *= 1 + mult return project @@ -332,12 +321,14 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['export_cable'] + scenario = self.sc_config["export_cable"] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'export_cable'." + ) + mult = 0.0 - project.system_costs['ExportCableInstallation'] *= (1 + mult) + project.system_costs["ExportCableInstallation"] *= 1 + mult return project diff --git a/docs/Makefile b/docs/Makefile index 298ea9e2..51285967 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 38ceb207..555a6637 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -sys.path.insert(0, os.path.abspath("..")) - import ORBIT +sys.path.insert(0, os.path.abspath("..")) + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 50478a79..0a3683f9 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW \ No newline at end of file +turbine_rating: 15 # MW diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 75b6fd5c..00a13ba3 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,31 +1,40 @@ -import pandas as pd +import os import math + import numpy as np +import pandas as pd import matplotlib as mpl -import matplotlib.pyplot as plt import matplotlib.text as txt -import os +import matplotlib.pyplot as plt -def mysave(fig, froot, mode='png'): - assert mode in ['png', 'eps', 'pdf', 'all'] + +def mysave(fig, froot, mode="png"): + assert mode in ["png", "eps", "pdf", "all"] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: legs.append(a.get_legend()) + if not addLeg is None: + legs.append(a.get_legend()) ext = [] - if mode == 'png' or mode == 'all': - ext.append('png') - if mode == 'eps': # or mode == 'all': - ext.append('eps') - if mode == 'pdf' or mode == 'all': - ext.append('pdf') + if mode == "png" or mode == "all": + ext.append("png") + if mode == "eps": # or mode == 'all': + ext.append("eps") + if mode == "pdf" or mode == "all": + ext.append("pdf") for sfx in ext: - fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', - dpi=dpiVal, bbox_extra_artists=legs) + fig.savefig( + fileName + "." + sfx, + format=sfx, + pad_inches=padding, + bbox_inches="tight", + dpi=dpiVal, + bbox_extra_artists=legs, + ) titleSize = 24 # 40 #38 @@ -38,32 +47,48 @@ def mysave(fig, froot, mode='png'): linewidth = 3 -def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): - assert type(mode) == type('') - assert mode.lower() in ['save', 'show'], 'Unknown mode' - - def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): - if mode.lower() == 'show': +def myformat( + ax, + linewidth=linewidth, + xticklabel=tickLabelSize, + yticklabel=tickLabelSize, + mode="save", +): + assert type(mode) == type("") + assert mode.lower() in ["save", "show"], "Unknown mode" + + def myformat( + myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel + ): + if mode.lower() == "show": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): + t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_title( + myax.get_title(), size=titleSize + deltaShow, weight="bold" + ) + myax.set_xlabel( + myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" + ) + myax.set_ylabel( + myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" + ) myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -75,27 +100,29 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == 'save': + elif mode.lower() == "save": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize) + for t in leg.get_texts(): + t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') + myax.set_title(myax.get_title(), size=titleSize, weight="bold") + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -108,40 +135,62 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl i.set_linewidth(3) if type(ax) == type([]): - for i in ax: myformat(i) + for i in ax: + myformat(i) else: myformat(ax) + def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax + def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """ Waterfall plot comparing European andUS manufactining costs""" + """Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') + h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) - ax.set_ylabel('Capital Expenditures, $/kW') - ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') - - h[3].set_linestyle('--') + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) + ) + ax.set_ylabel("Capital Expenditures, $/kW") + ax.set_title( + "Comparison of different cost premiums between \nimported and domestically manufactured components" + ) + + h[3].set_linestyle("--") h[3].set_linewidth(1.75) - h[3].set_edgecolor('k') - - ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) - ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) - ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) + h[3].set_edgecolor("k") + + ax.text( + x[1], + 2000, + bar_text["transit"], + horizontalalignment="center", + ) + ax.text( + x[2], + 2000, + bar_text["factory"], + horizontalalignment="center", + ) + ax.text( + x[3], + 2000, + bar_text["margin"], + horizontalalignment="center", + ) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() + def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -150,40 +199,52 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k,v in y.items()]) + y_init = np.sum([v[0] for k, v in y.items()]) - for k,v in y.items(): - y1 = [yi+vi for yi, vi in zip(y0,v)] + for k, v in y.items(): + y1 = [yi + vi for yi, vi in zip(y0, v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, 'w') + ax.plot(x, y1 / y_init, "w") y0 = y1 # Define margin - ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') + ax.fill_between( + x, + y1 / y_init, + np.ones(len(x)), + color=color["Cost margin"], + label="Margin", + ) - final_margin = round( 100* (1 - y1[-1] / y_init), 1) + final_margin = round(100 * (1 - y1[-1] / y_init), 1) - y_margin = ((1 + y1[-1] / y_init) /2) + y_margin = (1 + y1[-1] / y_init) / 2 - margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' + margin_text = ( + " " + + str(final_margin) + + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" + ) right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], 'k') - ax.text(right_bound, y_margin, margin_text, verticalalignment='center') - ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], "k") + ax.text(right_bound, y_margin, margin_text, verticalalignment="center") + ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') - ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') + ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") + ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") - ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') + ax.set_ylabel( + "CapEx breakdown relative to \ncomponents imported from Europe, %" + ) if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index 2b1bdafe..eed5b2c9 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,12 +12,10 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')" + "optional_input": "unit, (optional, default: 'default')", } - output_config = { - "example_output": "unit" - } + output_config = {"example_output": "unit"} def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -45,9 +43,7 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return { - "example_detailed_output": self.result - } + return {"example_detailed_output": self.result} @property def total_cost(self): @@ -60,9 +56,7 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return { - "example_output": self.result - } + return {"example_output": self.result} # === Annotated Example === @@ -75,18 +69,21 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": {"depth": "m"}, # For common inputs that will be shared across many modules, - "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules - "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT - - - + "site": { + "depth": "m" + }, # For common inputs that will be shared across many modules, + "plant": { + "num_turbines": "int" + }, # it's best to look up how the variable is named in existing modules + "turbine": { + "turbine_rating": "MW" + }, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -97,8 +94,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -114,13 +111,18 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above - - - self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library( + config, **kwargs + ) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config( + config + ) # if it hasn't already been and validate the config against '.expected_config' from above + + self._design = self.config.get( + "spar_design", {} + ) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -152,7 +154,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -174,8 +176,10 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get( + "stiffened_column_CR", 3120 + ) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -194,7 +198,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -219,7 +223,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -267,7 +271,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index e15c8156..4cc5fa25 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,7 +11,6 @@ def test_wisdem_monopile_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -23,7 +22,6 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -35,7 +33,6 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index a480e04e..5579f62c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,6 @@ import pytest from marmot import Environment - from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -24,27 +23,23 @@ def pytest_configure(): @pytest.fixture() def env(): - return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): - specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): - specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): - specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -53,7 +48,6 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): - specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -62,19 +56,16 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): - specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): - return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): - yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index 0ce94758..b5f5208b 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,7 +8,6 @@ import pandas as pd import pytest from marmot import le - from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 7320a9f6..9cac3f50 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -58,7 +57,6 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): - project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 915af401..6415118d 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,7 +8,6 @@ import pytest from marmot import Environment - from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -19,7 +18,6 @@ def __init__(self): def test_port_creation(): - env = Environment() port = Port(env) item = SampleItem() @@ -32,7 +30,6 @@ def test_port_creation(): def test_get_item(): - env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index cd1ad5cd..39c42a82 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -209,7 +208,6 @@ def test_correct_turbines(): def test_floating_calculations(): - base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index e1cf3024..ce7a1cd5 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,7 +11,6 @@ import numpy as np import pytest - from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -111,7 +110,6 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): - c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index 9db78fed..dbe18324 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,7 +8,6 @@ from copy import deepcopy import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -104,7 +103,6 @@ def test_design_result(): def test_floating_length_calculations(): - base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 0762b46b..2f69ed18 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,7 +10,6 @@ from itertools import product import pytest - from ORBIT.phases.design import MonopileDesign base = { @@ -37,7 +36,6 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): - config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -61,7 +59,6 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): - test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -80,7 +77,6 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -93,7 +89,6 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): - test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -107,7 +102,6 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index 88a7a747..c59ef535 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT.phases.design import MooringSystemDesign base = { @@ -21,7 +20,6 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): - config = deepcopy(base) config["site"]["depth"] = depth @@ -34,7 +32,6 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): - config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -46,7 +43,6 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): - m = MooringSystemDesign(base) m.run() @@ -75,7 +71,6 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): - config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index b2dd6316..f17b3bd7 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -24,7 +23,6 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -51,7 +49,6 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): - test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -72,7 +69,6 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index 301e5894..d4168fd1 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 7c710fb9..30a134f3 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index 393cf7c1..dbc937c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SparDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index 5a01c14b..f9b1c9a9 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ArrayCableInstallation(config) assert sim.env @@ -37,7 +35,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -53,7 +50,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -72,7 +68,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,7 +84,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -114,7 +108,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): - sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -131,7 +124,6 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -163,7 +155,6 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): - base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -183,7 +174,6 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index 3ab42d15..f3d03350 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -28,7 +27,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -59,7 +57,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index 34669075..e837176c 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -42,7 +40,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -58,7 +55,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -77,7 +73,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -94,7 +89,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -119,7 +113,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -150,7 +143,6 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -182,7 +174,6 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -214,7 +205,6 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index 6811e631..c601a5c6 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = JacketInstallation(config, weather=weather) sim.run() @@ -97,7 +93,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): - base = JacketInstallation(config) base.run() @@ -116,7 +111,6 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): - base = JacketInstallation(config) base.run() @@ -134,7 +128,6 @@ def test_foundation_type(config): def test_kwargs_piles(): - sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -154,7 +147,6 @@ def test_kwargs_piles(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -176,7 +168,6 @@ def test_kwargs_piles(): def test_kwargs_suction(): - config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -197,7 +188,6 @@ def test_kwargs_suction(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 57538063..1759bc3e 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = MonopileInstallation(config, weather=weather) sim.run() @@ -92,7 +88,6 @@ def test_for_complete_logging(weather, config): def test_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -113,7 +108,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -145,7 +139,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -168,7 +161,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -203,7 +195,6 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index bff023f5..2fa11d9e 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -35,7 +34,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -55,7 +53,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 116f7558..3583bbda 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -61,7 +60,6 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): - new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -74,7 +72,6 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -103,7 +100,6 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): - base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -117,7 +113,6 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index be32be3d..30ed4475 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -45,7 +43,6 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): - sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -58,7 +55,6 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -82,7 +78,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -104,7 +99,6 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): - sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -118,7 +112,6 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): - sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -139,7 +132,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -171,7 +163,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -195,7 +186,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 67a28c40..758df489 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -25,7 +24,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -44,7 +42,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index 00fa2b4e..b9a08bac 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -28,7 +27,6 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): - _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -54,7 +52,6 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): - _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -92,7 +89,6 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): - num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index dafad84b..25d7db92 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index e1fc0af7..72619642 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index 85e372c7..ae1c9313 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -51,7 +50,6 @@ def test_full_run_logging(weather): def test_kwargs(): - sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -61,7 +59,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -83,7 +80,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -96,7 +92,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index 6b600eb2..cba9802c 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,7 +9,6 @@ import pandas as pd import pytest from marmot import Environment - from ORBIT.phases.install import InstallPhase @@ -45,7 +44,6 @@ def setup_simulation(self): def test_abstract_methods(): - with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -53,7 +51,6 @@ def test_abstract_methods(): def test_run(): - sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index aac2de9f..0592999a 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): - sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -56,7 +54,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): - sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -80,7 +77,6 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): - sim = TurbineInstallation(config) assert sim.wtiv @@ -97,7 +93,6 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = TurbineInstallation(config, weather=weather) sim.run() @@ -120,7 +115,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): - sim = TurbineInstallation(config) sim.run() @@ -131,7 +125,6 @@ def test_for_complete_installation(config): def test_kwargs(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -153,7 +146,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -175,7 +167,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -200,7 +191,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} @@ -225,7 +215,6 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -245,7 +234,6 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): - vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 055da73d..2042f639 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -33,7 +32,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -56,7 +54,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 209983ac..01e37b7b 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,14 +18,12 @@ def test_good_config(): - config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): - config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -33,7 +31,6 @@ def test_missing_key(): def test_optional(): - config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -41,7 +38,6 @@ def test_optional(): def test_variable_key(): - config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -50,7 +46,6 @@ def test_variable_key(): def test_optional_dict(): - config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index f635f271..ffd84920 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,7 +7,6 @@ import os import pytest - from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -15,7 +14,6 @@ def test_save_and_load_equality(tmp_yaml_del): - save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -23,7 +21,6 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): - config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 059202fb..656db0d8 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,9 +6,8 @@ from copy import deepcopy -from numpy.testing import assert_almost_equal - from ORBIT import ProjectManager +from numpy.testing import assert_almost_equal from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -16,7 +15,6 @@ def test_fixed_phase_cost_passing(): - project = ProjectManager(fixed) project.run() @@ -47,7 +45,6 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): - project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 4d73da75..5d33cfca 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,9 +7,8 @@ import pandas as pd import pytest -from benedict import benedict - from ORBIT import ProjectManager, ParametricManager +from benedict import benedict from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -24,7 +23,6 @@ def test_for_equal_results(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -37,7 +35,6 @@ def test_for_equal_results(): def test_weather(): - without = ParametricManager(complete_project, params, funcs) without.run() @@ -50,7 +47,6 @@ def test_weather(): def test_individual_phase(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -67,7 +63,6 @@ def test_individual_phase(): def test_bad_result_attribute(): - funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -79,7 +74,6 @@ def test_bad_result_attribute(): def test_bad_result_structure(): - funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -91,7 +85,6 @@ def test_bad_result_structure(): def test_product_option(): - params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 7e62a225..9cbf9ad3 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,10 +8,9 @@ import pandas as pd import pytest - from ORBIT import ProjectManager -from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather +from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -26,10 +25,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") + ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): - project = ProjectManager(config, weather=weather) project.run() @@ -47,11 +46,9 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: - assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: - assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -130,7 +127,6 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: - i, expected = test response = TestProjectManager.find_key_match(i) @@ -143,13 +139,11 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: - assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): - config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -169,7 +163,6 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): - config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -233,7 +226,6 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): - config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -283,7 +275,6 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): - # Not a subclass class CustomInstallPhase: pass @@ -305,7 +296,6 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) - # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -318,11 +308,13 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase + assert ( + ProjectManager.find_key_match("CustomInstallPhase") + == CustomInstallPhase + ) def test_custom_design_phases(): - # Not a subclass class CustomDesignPhase: pass @@ -344,7 +336,6 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) - # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -357,11 +348,13 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + assert ( + ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + ) + ### Design Phase Interactions def test_design_phases(): - config_with_design = deepcopy(config) # Add MonopileDesign @@ -386,7 +379,6 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): - # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -467,7 +459,6 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): - incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -477,7 +468,6 @@ def test_incomplete_config(): def test_wrong_phases(): - wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -487,7 +477,6 @@ def test_wrong_phases(): def test_bad_dates(): - bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -500,7 +489,6 @@ def test_bad_dates(): def test_no_defined_start(): - missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -513,7 +501,6 @@ def test_no_defined_start(): def test_circular_dependencies(): - circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -532,7 +519,6 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): - wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -552,7 +538,6 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): - data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -592,7 +577,6 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): - project = ProjectManager(config) project.run() @@ -607,7 +591,6 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): - project = ProjectManager(complete_project) project.run() @@ -633,7 +616,6 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -649,7 +631,6 @@ def test_monthly_expenses(): def test_monthly_revenue(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -666,7 +647,6 @@ def test_monthly_revenue(): def test_cash_flow(): - project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -684,7 +664,6 @@ def test_cash_flow(): def test_npv(): - project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -721,7 +700,6 @@ def test_npv(): def test_soft_costs(): - project = ProjectManager(complete_project) baseline = project.soft_capex @@ -757,7 +735,6 @@ def test_soft_costs(): def test_project_costs(): - project = ProjectManager(complete_project) baseline = project.project_capex @@ -783,7 +760,6 @@ def test_project_costs(): def test_capex_categories(): - project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 64fea1c8..96361d2f 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,4 +1,3 @@ - # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -277,16 +276,18 @@ """ from __future__ import print_function + +import os +import re +import sys +import json +import errno +import subprocess + try: import configparser except ImportError: import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys class VersioneerConfig: @@ -308,11 +309,13 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") + err = ( + "Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND')." + ) raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -325,8 +328,10 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) + print( + "Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py) + ) except NameError: pass return root @@ -348,6 +353,7 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None + cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -372,17 +378,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -390,10 +399,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -418,7 +430,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return stdout, p.returncode -LONG_VERSION_PY['git'] = ''' +LONG_VERSION_PY[ + "git" +] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -993,7 +1007,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1002,7 +1016,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1010,19 +1024,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1037,8 +1058,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1046,10 +1068,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1072,17 +1103,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -1091,10 +1123,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1105,13 +1139,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1167,16 +1203,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1205,11 +1247,17 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1218,8 +1266,9 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps( + versions, sort_keys=True, indent=1, separators=(",", ": ") + ) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1251,8 +1300,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1366,11 +1414,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -1390,9 +1440,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } class VersioneerBadRootError(Exception): @@ -1415,8 +1469,9 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" + assert ( + cfg.versionfile_source is not None + ), "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1470,9 +1525,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } def get_version(): @@ -1521,6 +1580,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1553,14 +1613,17 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join( + self.build_lib, cfg.versionfile_build + ) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1581,17 +1644,21 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if 'py2exe' in sys.modules: # py2exe enabled? + if "py2exe" in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1610,13 +1677,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1643,8 +1714,10 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file( + target_versionfile, self._versioneer_generated_versions + ) + cmds["sdist"] = cmd_sdist return cmds @@ -1699,11 +1772,15 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except ( + EnvironmentError, + configparser.NoSectionError, + configparser.NoOptionError, + ) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print( + "Adding sample versioneer config to setup.cfg", file=sys.stderr + ) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1712,15 +1789,18 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1762,8 +1842,10 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print( + " appending versionfile_source ('%s') to MANIFEST.in" + % cfg.versionfile_source + ) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From 051b61f2fbd00380f812f42c32a68062474d5546 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 1 Mar 2023 13:40:06 -0700 Subject: [PATCH 09/19] Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" This reverts commit 0d3baeaa892147f24ac41f2eb61aa0ef97507a30. --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++------ ORBIT/api/wisdem.py | 1 + ORBIT/config.py | 1 + ORBIT/core/cargo.py | 1 + ORBIT/core/components.py | 1 + ORBIT/core/defaults/__init__.py | 1 + ORBIT/core/environment.py | 2 + ORBIT/core/exceptions.py | 1 + ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 + ORBIT/core/port.py | 1 + ORBIT/core/supply_chain.py | 1 + ORBIT/core/vessel.py | 2 + ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 + ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 8 +- ORBIT/phases/design/export_system_design.py | 2 + ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 + ORBIT/phases/install/cable_install/common.py | 1 + ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 + ORBIT/phases/install/jacket_install/common.py | 1 + .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 + .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 + ORBIT/phases/install/oss_install/common.py | 2 + ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 + .../quayside_assembly_tow/gravity_base.py | 3 + .../install/quayside_assembly_tow/moored.py | 3 + .../scour_protection_install/standard.py | 1 + .../phases/install/turbine_install/common.py | 1 + .../install/turbine_install/standard.py | 4 + ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 ++++------- templates/design_module.py | 74 ++--- tests/api/test_wisdem_api.py | 3 + tests/conftest.py | 9 + tests/core/test_environment.py | 1 + tests/core/test_library.py | 2 + tests/core/test_port.py | 3 + .../phases/design/test_array_system_design.py | 2 + tests/phases/design/test_cable.py | 2 + .../design/test_export_system_design.py | 2 + tests/phases/design/test_monopile_design.py | 6 + .../design/test_mooring_system_design.py | 5 + tests/phases/design/test_oss_design.py | 4 + .../design/test_scour_protection_design.py | 1 + .../design/test_semisubmersible_design.py | 4 + tests/phases/design/test_spar_design.py | 4 + .../cable_install/test_array_install.py | 10 + .../install/cable_install/test_cable_tasks.py | 3 + .../cable_install/test_export_install.py | 10 + .../jacket_install/test_jacket_install.py | 10 + .../monopile_install/test_monopile_install.py | 9 + .../monopile_install/test_monopile_tasks.py | 3 + .../mooring_install/test_mooring_install.py | 5 + .../install/oss_install/test_oss_install.py | 10 + .../install/oss_install/test_oss_tasks.py | 3 + .../quayside_assembly_tow/test_common.py | 4 + .../test_gravity_based.py | 3 + .../quayside_assembly_tow/test_moored.py | 3 + .../test_scour_protection.py | 5 + tests/phases/install/test_install_phase.py | 3 + .../turbine_install/test_turbine_install.py | 12 + .../turbine_install/test_turbine_tasks.py | 3 + tests/phases/test_base.py | 5 + tests/test_config_management.py | 3 + .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 ++- versioneer.py | 298 +++++++----------- 85 files changed, 716 insertions(+), 626 deletions(-) diff --git a/LICENSE b/LICENSE index 1c0c15ea..dbb692d8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index f03f6681..fa1e63bc 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,3 +1,4 @@ + # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -9,11 +10,11 @@ """Git implementation of _version.py.""" +import errno import os import re -import sys -import errno import subprocess +import sys def get_keywords(): @@ -57,20 +58,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -78,13 +76,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -121,22 +116,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -192,7 +181,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -201,7 +190,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -209,26 +198,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -243,9 +225,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -253,19 +234,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -288,18 +260,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -308,12 +279,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -324,15 +293,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -363,7 +330,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -477,13 +445,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -503,13 +469,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} def get_versions(): @@ -523,9 +485,8 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords( - get_keywords(), cfg.tag_prefix, verbose - ) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) except NotThisMethod: pass @@ -534,16 +495,13 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split("/"): + for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -557,10 +515,6 @@ def get_versions(): except NotThisMethod: pass - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 63fd1460..8320e99c 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,6 +7,7 @@ import openmdao.api as om + from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 5a416b43..4a50732d 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,6 +8,7 @@ import yaml from yaml import Dumper + from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index 0f618b4e..d02ab03f 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,6 +6,7 @@ class Cargo(Object): + def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index dec26889..e4e3792c 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,6 +6,7 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 1cc75bae..7df591ec 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,6 +8,7 @@ import os import yaml + from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index bade7d84..4654ec13 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,6 +88,7 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): + if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -138,6 +139,7 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): + if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index ec9fa5d6..8d7d0ca4 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,6 +31,7 @@ def __init__(self, vessel, component): ) def __str__(self): + return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index c8217b15..6f771cc0 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper + from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") - # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index daa4a707..b27a3e78 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -148,6 +149,7 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: + if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -260,13 +262,16 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: + if proposed_deck_space > vessel.storage.max_deck_space: + msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: + msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -327,6 +332,7 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: + vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index c24ccfa6..dbfc152a 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,6 +7,7 @@ import simpy + from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 6f271c9b..0f2f3e1a 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,6 +41,7 @@ def __init__( @process def start(self): + n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index c952e905..88c823a4 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,6 +15,7 @@ WindowNotFound, AgentNotRegistered, ) + from ORBIT.core.components import ( Crane, JackingSys, @@ -85,6 +86,7 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): + duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index ccb0a47d..6aeb5ba1 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,9 +14,10 @@ from itertools import product import numpy as np -import ORBIT import pandas as pd from benedict import benedict + +import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -166,12 +167,14 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): + try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): + idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -202,9 +205,7 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -228,9 +229,7 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -454,6 +453,7 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): + if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,6 +500,7 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): + ret = {} for k, t in self.phase_times.items(): try: @@ -692,6 +693,7 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): + _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -725,6 +727,7 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: + phases = {**phases, **skipped} if not phases: break @@ -823,6 +826,7 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): + if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1100,6 +1104,7 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): + unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1135,6 +1140,7 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): + start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 634b842c..6895400c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,10 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager + class ParametricManager: """Class for configuring parametric ORBIT runs.""" @@ -201,6 +202,7 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): + split = v.split("[") attr = split[0] @@ -296,6 +298,7 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): + if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 1b39d91a..2e9b539d 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,6 +10,7 @@ from copy import deepcopy from benedict import benedict + from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -69,6 +70,7 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): + if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 1b93d209..27343a58 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,6 +11,7 @@ import numpy as np from scipy.optimize import fsolve + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -332,7 +333,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 28b780d9..6fbf911d 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,6 +12,7 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt + from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -383,7 +384,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -578,6 +579,7 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): + ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -742,7 +744,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError @@ -812,6 +814,7 @@ def create_project_csv(self, save_name, folder="cables"): export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): + # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1059,6 +1062,7 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): + self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index bf7af015..6c6ae0a0 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,6 +6,7 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np + from ORBIT.phases.design._cables import CableSystem @@ -212,6 +213,7 @@ def design_result(self): } for name, cable in self.cables.items(): + output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index 082b3a9c..ab1e5349 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,6 +9,7 @@ from math import pi, log from scipy.optimize import fsolve + from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -229,7 +230,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp**2, + "deck_space": D_tp ** 2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -354,7 +355,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -559,7 +560,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 0dcf67d8..383a4924 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index ea72c993..1a2fe071 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,6 +7,7 @@ import numpy as np + from ORBIT.phases.design import DesignPhase @@ -283,7 +284,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass**0.5574 + substructure_pile_mass = 8 * substructure_mass ** 0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index d36b91eb..efa66b4f 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,6 +8,7 @@ from math import ceil import numpy as np + from ORBIT.phases.design import DesignPhase @@ -114,7 +115,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 7bb34217..58404a29 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating**2 + 6.54 * rating + 128.34 + mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index c8b0862e..224c4a5e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,6 +7,7 @@ from numpy import exp, log + from ORBIT.phases.design import DesignPhase @@ -71,7 +72,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -112,7 +113,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -137,7 +138,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index 21120126..d4d8a181 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,6 +10,7 @@ import numpy as np from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -236,6 +237,7 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: + try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -267,6 +269,7 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: + try: length, num_sections, *extra = sections.pop(0) if extra: @@ -288,10 +291,12 @@ def install_array_cables( break for _ in range(num_sections): + try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: + yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index fa0833f2..f2481138 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 55bf7d32..486bc9e7 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,6 +10,7 @@ from math import ceil from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -182,7 +183,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity**0.3549 + 350000 + onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index c4d159d6..97b93c3b 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,6 +12,7 @@ import numpy as np import simpy import pandas as pd + from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 5cd9feb2..4312bfcf 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,6 +5,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 10391d6e..2f8f0c55 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,6 +7,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -110,7 +111,9 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ """ + """ + + """ jacket = Jacket(**self.config["jacket"]) @@ -129,6 +132,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): + items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -369,6 +373,7 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -433,7 +438,9 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index ee1fcb74..04af017a 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,6 +7,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -339,6 +340,7 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 02c7c259..5a204709 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,6 +9,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -105,7 +106,9 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ """ + """ + + """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -116,6 +119,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): + delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -342,6 +346,7 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -403,7 +408,9 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index c4175f28..3b3573b9 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -160,7 +161,9 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: + system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f1c5527b..f90128ac 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -138,6 +139,7 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index a293363d..6580e19a 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,10 +6,11 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, le, process +from marmot import Agent, process, le +from marmot._exceptions import AgentNotRegistered + from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite -from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -143,6 +144,7 @@ def initialize_installation_vessel(self): @property def detailed_output(self): + return {} @@ -173,6 +175,7 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): + start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -193,7 +196,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range(3): + for _ in range (3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 15bcbd79..04038af9 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,6 +8,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -229,7 +230,9 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index a02a3547..4cbd97f6 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,6 +293,7 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -355,6 +357,7 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index 8376b274..c38908b2 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -291,6 +292,7 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -364,6 +366,7 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index db1c8ce6..9dd3ee9a 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,6 +10,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index f65aa7a3..057ff1bd 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index 58e273ab..d23515a1 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,6 +12,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -320,6 +321,7 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -405,7 +407,9 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index 8290eae7..b17e2ae8 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,47 +5,71 @@ from copy import deepcopy - -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager -DEFAULT_MULTIPLIERS = { - "blades": {"domestic": 0.026, "imported": 0.30}, - "nacelle": {"domestic": 0.025, "imported": 0.10}, - "tower": { - "domestic": 0.04, - "imported": 0.20, - "tariffs": 0.25, - }, - "monopile": { - "domestic": 0.085, - "imported": 0.28, - "tariffs": 0.25, - }, - "transition_piece": { - "domestic": 0.169, - "imported": 0.17, - "tariffs": 0.25, - }, - "array_cable": {"domestic": 0.19, "imported": 0.0}, - "export_cable": {"domestic": 0.231, "imported": 0.0}, - "oss_topside": {"domestic": 0.0, "imported": 0.0}, - "oss_substructure": {"domestic": 0.0, "imported": 0.0}, -} -TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} +DEFAULT_MULTIPLIERS = { + "blades": { + "domestic": .026, + "imported": .30 + }, + "nacelle": { + "domestic": .025, + "imported": .10 + }, + "tower": { + "domestic": .04, + "imported": .20, + "tariffs": .25, + }, + "monopile": { + "domestic": .085, + "imported": .28, + "tariffs": .25, + }, + "transition_piece": { + "domestic": .169, + "imported": .17, + "tariffs": .25, + }, + "array_cable": { + "domestic": .19, + "imported": 0. + }, + "export_cable": { + "domestic": .231, + "imported": 0. + }, + "oss_topside": { + "domestic": 0., + "imported": 0. + }, + "oss_substructure": { + "domestic": 0., + "imported": 0. + }, + } + + +TURBINE_CAPEX_SPLIT = { + "blades": 0.135, + "nacelle": 0.274, + "tower": 0.162 +} LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5, + "oss_topside": 0.5 } class SupplyChainManager: + def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -87,17 +111,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config["plant"]) + plant = deepcopy(config['plant']) # Run ProjectManager without install phases to generate design results - install_phases = config["install_phases"] - config["install_phases"] = [] + install_phases = config['install_phases'] + config['install_phases'] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config["plant"] = plant + config['plant'] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -106,8 +130,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config["install_phases"] = install_phases - config["design_phases"] = [] + config['install_phases'] = install_phases + config['design_phases'] = [] return config @@ -130,51 +154,45 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config["blades"] - nacelle_scenario = self.sc_config["nacelle"] - tower_scenario = self.sc_config["blades"] + blade_scenario = self.sc_config['blades'] + nacelle_scenario = self.sc_config['nacelle'] + tower_scenario = self.sc_config['blades'] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print( - f"Warning: scenario '{blade_scenario}' not found for category 'blades'." - ) - blade_mult = 0.0 + print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") + blade_mult = 0. nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print( - f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." - ) - nacelle_mult = 0.0 + print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") + nacelle_mult = 0. - raw_cost = config.get("project_parameters.turbine_capex", 1300) - blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult - nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult + raw_cost = config.get('project_parameters.turbine_capex', 1300) + blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult + nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = ( - raw_cost - * self.turbine_split["tower"] - * (1 - self.labor_split["tower"]) - * self.multipliers["tower"]["tariffs"] - ) + tower_tariffs = raw_cost * self.turbine_split['tower'] *\ + (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] else: - tower_tariffs = 0.0 + tower_tariffs = 0. tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print( - f"Warning: scenario '{tower_scenario}' not found for category 'tower'." - ) - tower_mult = 0.0 + print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") + tower_mult = 0. - tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult + tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult - config["project_parameters.turbine_capex"] = sum( - [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] - ) + config['project_parameters.turbine_capex'] = sum([ + raw_cost, + blade_adder, + nacelle_adder, + tower_adder, + tower_tariffs + ]) return config @@ -188,29 +206,28 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config["monopile.unit_cost"] - scenario = self.sc_config["monopile"] + raw_cost = config['monopile.unit_cost'] + scenario = self.sc_config['monopile'] if scenario == "domestic, imported steel": - adder = self.multipliers["monopile"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["monopile"]) - * self.multipliers["monopile"]["tariffs"] - ) + adder = self.multipliers['monopile']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ + self.multipliers["monopile"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'monopile'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") + mult = 0. adder = raw_cost * mult - config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['monopile.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -225,29 +242,28 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config["transition_piece.unit_cost"] - scenario = self.sc_config["transition_piece"] + raw_cost = config['transition_piece.unit_cost'] + scenario = self.sc_config['transition_piece'] if scenario == "domestic, imported steel": - adder = self.multipliers["transition_piece"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["transition_piece"]) - * self.multipliers["transition_piece"]["tariffs"] - ) + adder = self.multipliers['transition_piece']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ + self.multipliers["transition_piece"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'transition_piece'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") + mult = 0. adder = raw_cost * mult - config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['transition_piece.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -262,31 +278,28 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config["offshore_substation_topside.unit_cost"] - scenario = self.sc_config["oss_topside"] + raw_cost = config['offshore_substation_topside.unit_cost'] + scenario = self.sc_config['oss_topside'] if scenario == "domestic, imported steel": - adder = self.multipliers["oss_topside"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["oss_topside"]) - * self.multipliers["oss_topside"]["tariffs"] - ) + adder = self.multipliers['oss_topside']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ + self.multipliers["oss_topside"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'oss_topside'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") + mult = 0. adder = raw_cost * mult - config["offshore_substation_topside.unit_cost"] = sum( - [raw_cost, adder, tariffs] - ) + config['offshore_substation_topside.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -300,15 +313,13 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["array_cable"] + scenario = self.sc_config['array_cable'] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'array_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") + mult = 0. - project.system_costs["ArrayCableInstallation"] *= 1 + mult + project.system_costs['ArrayCableInstallation'] *= (1 + mult) return project @@ -321,14 +332,12 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["export_cable"] + scenario = self.sc_config['export_cable'] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'export_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") + mult = 0. - project.system_costs["ExportCableInstallation"] *= 1 + mult + project.system_costs['ExportCableInstallation'] *= (1 + mult) return project diff --git a/docs/Makefile b/docs/Makefile index 51285967..298ea9e2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 555a6637..38ceb207 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -import ORBIT - sys.path.insert(0, os.path.abspath("..")) +import ORBIT + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 0a3683f9..50478a79 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW +turbine_rating: 15 # MW \ No newline at end of file diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 00a13ba3..75b6fd5c 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,40 +1,31 @@ -import os +import pandas as pd import math - import numpy as np -import pandas as pd import matplotlib as mpl -import matplotlib.text as txt import matplotlib.pyplot as plt +import matplotlib.text as txt +import os - -def mysave(fig, froot, mode="png"): - assert mode in ["png", "eps", "pdf", "all"] +def mysave(fig, froot, mode='png'): + assert mode in ['png', 'eps', 'pdf', 'all'] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: - legs.append(a.get_legend()) + if not addLeg is None: legs.append(a.get_legend()) ext = [] - if mode == "png" or mode == "all": - ext.append("png") - if mode == "eps": # or mode == 'all': - ext.append("eps") - if mode == "pdf" or mode == "all": - ext.append("pdf") + if mode == 'png' or mode == 'all': + ext.append('png') + if mode == 'eps': # or mode == 'all': + ext.append('eps') + if mode == 'pdf' or mode == 'all': + ext.append('pdf') for sfx in ext: - fig.savefig( - fileName + "." + sfx, - format=sfx, - pad_inches=padding, - bbox_inches="tight", - dpi=dpiVal, - bbox_extra_artists=legs, - ) + fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', + dpi=dpiVal, bbox_extra_artists=legs) titleSize = 24 # 40 #38 @@ -47,48 +38,32 @@ def mysave(fig, froot, mode="png"): linewidth = 3 -def myformat( - ax, - linewidth=linewidth, - xticklabel=tickLabelSize, - yticklabel=tickLabelSize, - mode="save", -): - assert type(mode) == type("") - assert mode.lower() in ["save", "show"], "Unknown mode" - - def myformat( - myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel - ): - if mode.lower() == "show": +def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): + assert type(mode) == type('') + assert mode.lower() in ['save', 'show'], 'Unknown mode' + + def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): + if mode.lower() == 'show': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title( - myax.get_title(), size=titleSize + deltaShow, weight="bold" - ) - myax.set_xlabel( - myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" - ) - myax.set_ylabel( - myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" - ) + myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -100,29 +75,27 @@ def myformat( for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == "save": + elif mode.lower() == 'save': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize) + for t in leg.get_texts(): t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight="bold") - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") + myax.set_title(myax.get_title(), size=titleSize, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -135,62 +108,40 @@ def myformat( i.set_linewidth(3) if type(ax) == type([]): - for i in ax: - myformat(i) + for i in ax: myformat(i) else: myformat(ax) - def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax - def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """Waterfall plot comparing European andUS manufactining costs""" + """ Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") + h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) - ) - ax.set_ylabel("Capital Expenditures, $/kW") - ax.set_title( - "Comparison of different cost premiums between \nimported and domestically manufactured components" - ) - - h[3].set_linestyle("--") + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) + ax.set_ylabel('Capital Expenditures, $/kW') + ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') + + h[3].set_linestyle('--') h[3].set_linewidth(1.75) - h[3].set_edgecolor("k") - - ax.text( - x[1], - 2000, - bar_text["transit"], - horizontalalignment="center", - ) - ax.text( - x[2], - 2000, - bar_text["factory"], - horizontalalignment="center", - ) - ax.text( - x[3], - 2000, - bar_text["margin"], - horizontalalignment="center", - ) + h[3].set_edgecolor('k') + + ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) + ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) + ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() - def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -199,52 +150,40 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k, v in y.items()]) + y_init = np.sum([v[0] for k,v in y.items()]) - for k, v in y.items(): - y1 = [yi + vi for yi, vi in zip(y0, v)] + for k,v in y.items(): + y1 = [yi+vi for yi, vi in zip(y0,v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, "w") + ax.plot(x, y1 / y_init, 'w') y0 = y1 # Define margin - ax.fill_between( - x, - y1 / y_init, - np.ones(len(x)), - color=color["Cost margin"], - label="Margin", - ) + ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') - final_margin = round(100 * (1 - y1[-1] / y_init), 1) + final_margin = round( 100* (1 - y1[-1] / y_init), 1) - y_margin = (1 + y1[-1] / y_init) / 2 + y_margin = ((1 + y1[-1] / y_init) /2) - margin_text = ( - " " - + str(final_margin) - + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" - ) + margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], "k") - ax.text(right_bound, y_margin, margin_text, verticalalignment="center") - ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], 'k') + ax.text(right_bound, y_margin, margin_text, verticalalignment='center') + ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") - ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") + ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') + ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') - ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel( - "CapEx breakdown relative to \ncomponents imported from Europe, %" - ) + ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index eed5b2c9..2b1bdafe 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,10 +12,12 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')", + "optional_input": "unit, (optional, default: 'default')" } - output_config = {"example_output": "unit"} + output_config = { + "example_output": "unit" + } def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -43,7 +45,9 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return {"example_detailed_output": self.result} + return { + "example_detailed_output": self.result + } @property def total_cost(self): @@ -56,7 +60,9 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return {"example_output": self.result} + return { + "example_output": self.result + } # === Annotated Example === @@ -69,21 +75,18 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": { - "depth": "m" - }, # For common inputs that will be shared across many modules, - "plant": { - "num_turbines": "int" - }, # it's best to look up how the variable is named in existing modules - "turbine": { - "turbine_rating": "MW" - }, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + "site": {"depth": "m"}, # For common inputs that will be shared across many modules, + "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules + "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + + + # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -94,8 +97,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -111,18 +114,13 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library( - config, **kwargs - ) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config( - config - ) # if it hasn't already been and validate the config against '.expected_config' from above - - self._design = self.config.get( - "spar_design", {} - ) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above + + + self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -154,7 +152,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -176,10 +174,8 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get( - "stiffened_column_CR", 3120 - ) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -198,7 +194,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -223,7 +219,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -271,7 +267,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index 4cc5fa25..e15c8156 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,6 +11,7 @@ def test_wisdem_monopile_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -22,6 +23,7 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -33,6 +35,7 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index 5579f62c..a480e04e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ import pytest from marmot import Environment + from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -23,23 +24,27 @@ def pytest_configure(): @pytest.fixture() def env(): + return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): + specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): + specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): + specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -48,6 +53,7 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): + specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -56,16 +62,19 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): + specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): + return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): + yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index b5f5208b..0ce94758 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,6 +8,7 @@ import pandas as pd import pytest from marmot import le + from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 9cac3f50..7320a9f6 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -57,6 +58,7 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): + project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 6415118d..915af401 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,6 +8,7 @@ import pytest from marmot import Environment + from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -18,6 +19,7 @@ def __init__(self): def test_port_creation(): + env = Environment() port = Port(env) item = SampleItem() @@ -30,6 +32,7 @@ def test_port_creation(): def test_get_item(): + env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index 39c42a82..cd1ad5cd 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -208,6 +209,7 @@ def test_correct_turbines(): def test_floating_calculations(): + base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index ce7a1cd5..e1cf3024 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,6 +11,7 @@ import numpy as np import pytest + from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -110,6 +111,7 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): + c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index dbe18324..9db78fed 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,6 +8,7 @@ from copy import deepcopy import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -103,6 +104,7 @@ def test_design_result(): def test_floating_length_calculations(): + base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 2f69ed18..0762b46b 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,6 +10,7 @@ from itertools import product import pytest + from ORBIT.phases.design import MonopileDesign base = { @@ -36,6 +37,7 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): + config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -59,6 +61,7 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): + test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -77,6 +80,7 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -89,6 +93,7 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): + test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -102,6 +107,7 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index c59ef535..88a7a747 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT.phases.design import MooringSystemDesign base = { @@ -20,6 +21,7 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): + config = deepcopy(base) config["site"]["depth"] = depth @@ -32,6 +34,7 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): + config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -43,6 +46,7 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): + m = MooringSystemDesign(base) m.run() @@ -71,6 +75,7 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): + config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index f17b3bd7..b2dd6316 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -23,6 +24,7 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -49,6 +51,7 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): + test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -69,6 +72,7 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index d4168fd1..301e5894 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 30a134f3..7c710fb9 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index dbc937c1..393cf7c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SparDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index f9b1c9a9..5a01c14b 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ArrayCableInstallation(config) assert sim.env @@ -35,6 +37,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -50,6 +53,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -68,6 +72,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -84,6 +89,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -108,6 +114,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): + sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -124,6 +131,7 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -155,6 +163,7 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): + base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -174,6 +183,7 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index f3d03350..3ab42d15 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -27,6 +28,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -57,6 +59,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index e837176c..34669075 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -40,6 +42,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -55,6 +58,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -73,6 +77,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,6 +94,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -113,6 +119,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -143,6 +150,7 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -174,6 +182,7 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -205,6 +214,7 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index c601a5c6..6811e631 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = JacketInstallation(config, weather=weather) sim.run() @@ -93,6 +97,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): + base = JacketInstallation(config) base.run() @@ -111,6 +116,7 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): + base = JacketInstallation(config) base.run() @@ -128,6 +134,7 @@ def test_foundation_type(config): def test_kwargs_piles(): + sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -147,6 +154,7 @@ def test_kwargs_piles(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -168,6 +176,7 @@ def test_kwargs_piles(): def test_kwargs_suction(): + config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -188,6 +197,7 @@ def test_kwargs_suction(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 1759bc3e..57538063 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = MonopileInstallation(config, weather=weather) sim.run() @@ -88,6 +92,7 @@ def test_for_complete_logging(weather, config): def test_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -108,6 +113,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -139,6 +145,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -161,6 +168,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -195,6 +203,7 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index 2fa11d9e..bff023f5 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -34,6 +35,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -53,6 +55,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 3583bbda..116f7558 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -60,6 +61,7 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): + new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -72,6 +74,7 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -100,6 +103,7 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): + base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -113,6 +117,7 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index 30ed4475..be32be3d 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -43,6 +45,7 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): + sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -55,6 +58,7 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -78,6 +82,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -99,6 +104,7 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): + sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -112,6 +118,7 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): + sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -132,6 +139,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -163,6 +171,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -186,6 +195,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 758df489..67a28c40 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -24,6 +25,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -42,6 +44,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index b9a08bac..00fa2b4e 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -27,6 +28,7 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): + _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -52,6 +54,7 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): + _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -89,6 +92,7 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): + num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index 25d7db92..dafad84b 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index 72619642..e1fc0af7 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index ae1c9313..85e372c7 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -50,6 +51,7 @@ def test_full_run_logging(weather): def test_kwargs(): + sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -59,6 +61,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -80,6 +83,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -92,6 +96,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index cba9802c..6b600eb2 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,6 +9,7 @@ import pandas as pd import pytest from marmot import Environment + from ORBIT.phases.install import InstallPhase @@ -44,6 +45,7 @@ def setup_simulation(self): def test_abstract_methods(): + with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -51,6 +53,7 @@ def test_abstract_methods(): def test_run(): + sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index 0592999a..aac2de9f 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): + sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -54,6 +56,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): + sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -77,6 +80,7 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): + sim = TurbineInstallation(config) assert sim.wtiv @@ -93,6 +97,7 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = TurbineInstallation(config, weather=weather) sim.run() @@ -115,6 +120,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): + sim = TurbineInstallation(config) sim.run() @@ -125,6 +131,7 @@ def test_for_complete_installation(config): def test_kwargs(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -146,6 +153,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -167,6 +175,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -191,6 +200,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} @@ -215,6 +225,7 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -234,6 +245,7 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): + vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 2042f639..055da73d 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -32,6 +33,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -54,6 +56,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 01e37b7b..209983ac 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,12 +18,14 @@ def test_good_config(): + config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): + config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -31,6 +33,7 @@ def test_missing_key(): def test_optional(): + config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -38,6 +41,7 @@ def test_optional(): def test_variable_key(): + config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -46,6 +50,7 @@ def test_variable_key(): def test_optional_dict(): + config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index ffd84920..f635f271 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,6 +7,7 @@ import os import pytest + from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -14,6 +15,7 @@ def test_save_and_load_equality(tmp_yaml_del): + save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -21,6 +23,7 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): + config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 656db0d8..059202fb 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,8 +6,9 @@ from copy import deepcopy -from ORBIT import ProjectManager from numpy.testing import assert_almost_equal + +from ORBIT import ProjectManager from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -15,6 +16,7 @@ def test_fixed_phase_cost_passing(): + project = ProjectManager(fixed) project.run() @@ -45,6 +47,7 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): + project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 5d33cfca..4d73da75 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,8 +7,9 @@ import pandas as pd import pytest -from ORBIT import ProjectManager, ParametricManager from benedict import benedict + +from ORBIT import ProjectManager, ParametricManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -23,6 +24,7 @@ def test_for_equal_results(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -35,6 +37,7 @@ def test_for_equal_results(): def test_weather(): + without = ParametricManager(complete_project, params, funcs) without.run() @@ -47,6 +50,7 @@ def test_weather(): def test_individual_phase(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -63,6 +67,7 @@ def test_individual_phase(): def test_bad_result_attribute(): + funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -74,6 +79,7 @@ def test_bad_result_attribute(): def test_bad_result_structure(): + funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -85,6 +91,7 @@ def test_bad_result_structure(): def test_product_option(): + params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 9cbf9ad3..7e62a225 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,9 +8,10 @@ import pandas as pd import pytest + from ORBIT import ProjectManager +from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather -from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -25,10 +26,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") - ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): + project = ProjectManager(config, weather=weather) project.run() @@ -46,9 +47,11 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: + assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: + assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -127,6 +130,7 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: + i, expected = test response = TestProjectManager.find_key_match(i) @@ -139,11 +143,13 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: + assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): + config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -163,6 +169,7 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): + config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -226,6 +233,7 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): + config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -275,6 +283,7 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): + # Not a subclass class CustomInstallPhase: pass @@ -296,6 +305,7 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) + # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -308,13 +318,11 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ( - ProjectManager.find_key_match("CustomInstallPhase") - == CustomInstallPhase - ) + assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase def test_custom_design_phases(): + # Not a subclass class CustomDesignPhase: pass @@ -336,6 +344,7 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) + # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -348,13 +357,11 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ( - ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase - ) - + assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase ### Design Phase Interactions def test_design_phases(): + config_with_design = deepcopy(config) # Add MonopileDesign @@ -379,6 +386,7 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): + # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -459,6 +467,7 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): + incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -468,6 +477,7 @@ def test_incomplete_config(): def test_wrong_phases(): + wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -477,6 +487,7 @@ def test_wrong_phases(): def test_bad_dates(): + bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -489,6 +500,7 @@ def test_bad_dates(): def test_no_defined_start(): + missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -501,6 +513,7 @@ def test_no_defined_start(): def test_circular_dependencies(): + circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -519,6 +532,7 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): + wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -538,6 +552,7 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): + data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -577,6 +592,7 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): + project = ProjectManager(config) project.run() @@ -591,6 +607,7 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): + project = ProjectManager(complete_project) project.run() @@ -616,6 +633,7 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -631,6 +649,7 @@ def test_monthly_expenses(): def test_monthly_revenue(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -647,6 +666,7 @@ def test_monthly_revenue(): def test_cash_flow(): + project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -664,6 +684,7 @@ def test_cash_flow(): def test_npv(): + project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -700,6 +721,7 @@ def test_npv(): def test_soft_costs(): + project = ProjectManager(complete_project) baseline = project.soft_capex @@ -735,6 +757,7 @@ def test_soft_costs(): def test_project_costs(): + project = ProjectManager(complete_project) baseline = project.project_capex @@ -760,6 +783,7 @@ def test_project_costs(): def test_capex_categories(): + project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 96361d2f..64fea1c8 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,3 +1,4 @@ + # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -276,18 +277,16 @@ """ from __future__ import print_function - -import os -import re -import sys -import json -import errno -import subprocess - try: import configparser except ImportError: import ConfigParser as configparser +import errno +import json +import os +import re +import subprocess +import sys class VersioneerConfig: @@ -309,13 +308,11 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ( - "Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND')." - ) + err = ("Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -328,10 +325,8 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print( - "Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py) - ) + print("Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py)) except NameError: pass return root @@ -353,7 +348,6 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None - cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -378,20 +372,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -399,13 +390,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -430,9 +418,7 @@ def run_command( return stdout, p.returncode -LONG_VERSION_PY[ - "git" -] = ''' +LONG_VERSION_PY['git'] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -1007,7 +993,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1016,7 +1002,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1024,26 +1010,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -1058,9 +1037,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1068,19 +1046,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1103,18 +1072,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -1123,12 +1091,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1139,15 +1105,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1203,22 +1167,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1247,17 +1205,11 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search( - r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: - mo = re.search( - r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1266,9 +1218,8 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps( - versions, sort_keys=True, indent=1, separators=(",", ": ") - ) + contents = json.dumps(versions, sort_keys=True, + indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1300,7 +1251,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1414,13 +1366,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -1440,13 +1390,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} class VersioneerBadRootError(Exception): @@ -1469,9 +1415,8 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert ( - cfg.versionfile_source is not None - ), "please set versioneer.versionfile_source" + assert cfg.versionfile_source is not None, \ + "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1525,13 +1470,9 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, "error": "unable to compute version", + "date": None} def get_version(): @@ -1580,7 +1521,6 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1613,17 +1553,14 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join( - self.build_lib, cfg.versionfile_build - ) + target_versionfile = os.path.join(self.build_lib, + cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1644,21 +1581,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if "py2exe" in sys.modules: # py2exe enabled? + if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1677,17 +1610,13 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1714,10 +1643,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file( - target_versionfile, self._versioneer_generated_versions - ) - + write_to_version_file(target_versionfile, + self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds @@ -1772,15 +1699,11 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except ( - EnvironmentError, - configparser.NoSectionError, - configparser.NoOptionError, - ) as e: + except (EnvironmentError, configparser.NoSectionError, + configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print( - "Adding sample versioneer config to setup.cfg", file=sys.stderr - ) + print("Adding sample versioneer config to setup.cfg", + file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1789,18 +1712,15 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") + f.write(LONG % {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), + "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1842,10 +1762,8 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print( - " appending versionfile_source ('%s') to MANIFEST.in" - % cfg.versionfile_source - ) + print(" appending versionfile_source ('%s') to MANIFEST.in" % + cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From 8493b8072754092f7082a3462246be4ef821f14e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:41:12 +0000 Subject: [PATCH 10/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++++---- ORBIT/api/wisdem.py | 1 - ORBIT/config.py | 1 - ORBIT/core/cargo.py | 1 - ORBIT/core/components.py | 1 - ORBIT/core/defaults/__init__.py | 1 - ORBIT/core/environment.py | 2 - ORBIT/core/exceptions.py | 1 - ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 - ORBIT/core/port.py | 1 - ORBIT/core/supply_chain.py | 1 - ORBIT/core/vessel.py | 2 - ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 - ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 8 +- ORBIT/phases/design/export_system_design.py | 2 - ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 - ORBIT/phases/install/cable_install/common.py | 1 - ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 - ORBIT/phases/install/jacket_install/common.py | 1 - .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 - .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 - ORBIT/phases/install/oss_install/common.py | 2 - ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 - .../quayside_assembly_tow/gravity_base.py | 3 - .../install/quayside_assembly_tow/moored.py | 3 - .../scour_protection_install/standard.py | 1 - .../phases/install/turbine_install/common.py | 1 - .../install/turbine_install/standard.py | 4 - ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 +++++++---- templates/design_module.py | 74 +++-- tests/api/test_wisdem_api.py | 3 - tests/conftest.py | 9 - tests/core/test_environment.py | 1 - tests/core/test_library.py | 2 - tests/core/test_port.py | 3 - .../phases/design/test_array_system_design.py | 2 - tests/phases/design/test_cable.py | 2 - .../design/test_export_system_design.py | 2 - tests/phases/design/test_monopile_design.py | 6 - .../design/test_mooring_system_design.py | 5 - tests/phases/design/test_oss_design.py | 4 - .../design/test_scour_protection_design.py | 1 - .../design/test_semisubmersible_design.py | 4 - tests/phases/design/test_spar_design.py | 4 - .../cable_install/test_array_install.py | 10 - .../install/cable_install/test_cable_tasks.py | 3 - .../cable_install/test_export_install.py | 10 - .../jacket_install/test_jacket_install.py | 10 - .../monopile_install/test_monopile_install.py | 9 - .../monopile_install/test_monopile_tasks.py | 3 - .../mooring_install/test_mooring_install.py | 5 - .../install/oss_install/test_oss_install.py | 10 - .../install/oss_install/test_oss_tasks.py | 3 - .../quayside_assembly_tow/test_common.py | 4 - .../test_gravity_based.py | 3 - .../quayside_assembly_tow/test_moored.py | 3 - .../test_scour_protection.py | 5 - tests/phases/install/test_install_phase.py | 3 - .../turbine_install/test_turbine_install.py | 12 - .../turbine_install/test_turbine_tasks.py | 3 - tests/phases/test_base.py | 5 - tests/test_config_management.py | 3 - .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 +-- versioneer.py | 298 +++++++++++------- 85 files changed, 626 insertions(+), 716 deletions(-) diff --git a/LICENSE b/LICENSE index dbb692d8..1c0c15ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index fa1e63bc..f03f6681 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,4 +1,3 @@ - # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -10,11 +9,11 @@ """Git implementation of _version.py.""" -import errno import os import re -import subprocess import sys +import errno +import subprocess def get_keywords(): @@ -58,17 +57,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -76,10 +78,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -116,16 +121,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -181,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -190,7 +201,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -198,19 +209,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -225,8 +243,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -234,10 +253,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -260,17 +288,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -279,10 +308,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -293,13 +324,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -330,8 +363,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -445,11 +477,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -469,9 +503,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } def get_versions(): @@ -485,8 +523,9 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) + return git_versions_from_keywords( + get_keywords(), cfg.tag_prefix, verbose + ) except NotThisMethod: pass @@ -495,13 +534,16 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): + for i in cfg.versionfile_source.split("/"): root = os.path.dirname(root) except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None, + } try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -515,6 +557,10 @@ def get_versions(): except NotThisMethod: pass - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 8320e99c..63fd1460 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,7 +7,6 @@ import openmdao.api as om - from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 4a50732d..5a416b43 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,7 +8,6 @@ import yaml from yaml import Dumper - from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index d02ab03f..0f618b4e 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,7 +6,6 @@ class Cargo(Object): - def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index e4e3792c..dec26889 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,7 +6,6 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 7df591ec..1cc75bae 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,7 +8,6 @@ import os import yaml - from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index 4654ec13..bade7d84 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,7 +88,6 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): - if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -139,7 +138,6 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): - if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index 8d7d0ca4..ec9fa5d6 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,7 +31,6 @@ def __init__(self, vessel, component): ) def __str__(self): - return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index 6f771cc0..c8217b15 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper - from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") + # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index b27a3e78..daa4a707 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -149,7 +148,6 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: - if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -262,16 +260,13 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: - if proposed_deck_space > vessel.storage.max_deck_space: - msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: - msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -332,7 +327,6 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: - vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index dbfc152a..c24ccfa6 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,7 +7,6 @@ import simpy - from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 0f2f3e1a..6f271c9b 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,7 +41,6 @@ def __init__( @process def start(self): - n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index 88c823a4..c952e905 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,7 +15,6 @@ WindowNotFound, AgentNotRegistered, ) - from ORBIT.core.components import ( Crane, JackingSys, @@ -86,7 +85,6 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): - duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 6aeb5ba1..ccb0a47d 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,10 +14,9 @@ from itertools import product import numpy as np +import ORBIT import pandas as pd from benedict import benedict - -import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -167,14 +166,12 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): - try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): - idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -205,7 +202,9 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -229,7 +228,9 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -453,7 +454,6 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): - if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,7 +500,6 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): - ret = {} for k, t in self.phase_times.items(): try: @@ -693,7 +692,6 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): - _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -727,7 +725,6 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: - phases = {**phases, **skipped} if not phases: break @@ -826,7 +823,6 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): - if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1104,7 +1100,6 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): - unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1140,7 +1135,6 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): - start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 6895400c..634b842c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,8 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from benedict import benedict - from ORBIT import ProjectManager +from benedict import benedict class ParametricManager: @@ -202,7 +201,6 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): - split = v.split("[") attr = split[0] @@ -298,7 +296,6 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): - if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 2e9b539d..1b39d91a 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,7 +10,6 @@ from copy import deepcopy from benedict import benedict - from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -70,7 +69,6 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): - if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 27343a58..1b93d209 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,7 +11,6 @@ import numpy as np from scipy.optimize import fsolve - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -333,7 +332,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 6fbf911d..28b780d9 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,7 +12,6 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt - from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -384,7 +383,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -579,7 +578,6 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): - ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -744,7 +742,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError @@ -814,7 +812,6 @@ def create_project_csv(self, save_name, folder="cables"): export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): - # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1062,7 +1059,6 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): - self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index 6c6ae0a0..bf7af015 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,7 +6,6 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np - from ORBIT.phases.design._cables import CableSystem @@ -213,7 +212,6 @@ def design_result(self): } for name, cable in self.cables.items(): - output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index ab1e5349..082b3a9c 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,7 +9,6 @@ from math import pi, log from scipy.optimize import fsolve - from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -230,7 +229,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp ** 2, + "deck_space": D_tp**2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -355,7 +354,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -560,7 +559,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 383a4924..0dcf67d8 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index 1a2fe071..ea72c993 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,7 +7,6 @@ import numpy as np - from ORBIT.phases.design import DesignPhase @@ -284,7 +283,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass ** 0.5574 + substructure_pile_mass = 8 * substructure_mass**0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index efa66b4f..d36b91eb 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,7 +8,6 @@ from math import ceil import numpy as np - from ORBIT.phases.design import DesignPhase @@ -115,7 +114,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 58404a29..7bb34217 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 + mass = -0.153 * rating**2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index 224c4a5e..c8b0862e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,7 +7,6 @@ from numpy import exp, log - from ORBIT.phases.design import DesignPhase @@ -72,7 +71,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -113,7 +112,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -138,7 +137,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index d4d8a181..21120126 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,7 +10,6 @@ import numpy as np from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -237,7 +236,6 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: - try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -269,7 +267,6 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: - try: length, num_sections, *extra = sections.pop(0) if extra: @@ -291,12 +288,10 @@ def install_array_cables( break for _ in range(num_sections): - try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: - yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index f2481138..fa0833f2 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 486bc9e7..55bf7d32 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,7 +10,6 @@ from math import ceil from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -183,7 +182,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 + onshore_misc_cost = 11795 * capacity**0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index 97b93c3b..c4d159d6 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,7 +12,6 @@ import numpy as np import simpy import pandas as pd - from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 4312bfcf..5cd9feb2 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,7 +5,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 2f8f0c55..10391d6e 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,7 +7,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -111,9 +110,7 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ - - """ + """ """ jacket = Jacket(**self.config["jacket"]) @@ -132,7 +129,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): - items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -373,7 +369,6 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -438,9 +433,7 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index 04af017a..ee1fcb74 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,7 +7,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -340,7 +339,6 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 5a204709..02c7c259 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,7 +9,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -106,9 +105,7 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ - - """ + """ """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -119,7 +116,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): - delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -346,7 +342,6 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -408,9 +403,7 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index 3b3573b9..c4175f28 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -161,9 +160,7 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: - system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f90128ac..f1c5527b 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -139,7 +138,6 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index 6580e19a..a293363d 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,11 +6,10 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, process, le -from marmot._exceptions import AgentNotRegistered - +from marmot import Agent, le, process from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite +from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -144,7 +143,6 @@ def initialize_installation_vessel(self): @property def detailed_output(self): - return {} @@ -175,7 +173,6 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): - start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -196,7 +193,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range (3): + for _ in range(3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 04038af9..15bcbd79 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,7 +8,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -230,9 +229,7 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index 4cbd97f6..a02a3547 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -293,7 +292,6 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -357,7 +355,6 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index c38908b2..8376b274 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,7 +291,6 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -366,7 +364,6 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index 9dd3ee9a..db1c8ce6 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,7 +10,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index 057ff1bd..f65aa7a3 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index d23515a1..58e273ab 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,7 +12,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -321,7 +320,6 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -407,9 +405,7 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index b17e2ae8..8290eae7 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,71 +5,47 @@ from copy import deepcopy -from benedict import benedict -from ORBIT import ProjectManager - +from ORBIT import ProjectManager +from benedict import benedict DEFAULT_MULTIPLIERS = { - "blades": { - "domestic": .026, - "imported": .30 - }, - "nacelle": { - "domestic": .025, - "imported": .10 - }, - "tower": { - "domestic": .04, - "imported": .20, - "tariffs": .25, - }, - "monopile": { - "domestic": .085, - "imported": .28, - "tariffs": .25, - }, - "transition_piece": { - "domestic": .169, - "imported": .17, - "tariffs": .25, - }, - "array_cable": { - "domestic": .19, - "imported": 0. - }, - "export_cable": { - "domestic": .231, - "imported": 0. - }, - "oss_topside": { - "domestic": 0., - "imported": 0. - }, - "oss_substructure": { - "domestic": 0., - "imported": 0. - }, - } - - -TURBINE_CAPEX_SPLIT = { - "blades": 0.135, - "nacelle": 0.274, - "tower": 0.162 + "blades": {"domestic": 0.026, "imported": 0.30}, + "nacelle": {"domestic": 0.025, "imported": 0.10}, + "tower": { + "domestic": 0.04, + "imported": 0.20, + "tariffs": 0.25, + }, + "monopile": { + "domestic": 0.085, + "imported": 0.28, + "tariffs": 0.25, + }, + "transition_piece": { + "domestic": 0.169, + "imported": 0.17, + "tariffs": 0.25, + }, + "array_cable": {"domestic": 0.19, "imported": 0.0}, + "export_cable": {"domestic": 0.231, "imported": 0.0}, + "oss_topside": {"domestic": 0.0, "imported": 0.0}, + "oss_substructure": {"domestic": 0.0, "imported": 0.0}, } +TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} + + LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5 + "oss_topside": 0.5, } class SupplyChainManager: - def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -111,17 +87,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config['plant']) + plant = deepcopy(config["plant"]) # Run ProjectManager without install phases to generate design results - install_phases = config['install_phases'] - config['install_phases'] = [] + install_phases = config["install_phases"] + config["install_phases"] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config['plant'] = plant + config["plant"] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -130,8 +106,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config['install_phases'] = install_phases - config['design_phases'] = [] + config["install_phases"] = install_phases + config["design_phases"] = [] return config @@ -154,45 +130,51 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config['blades'] - nacelle_scenario = self.sc_config['nacelle'] - tower_scenario = self.sc_config['blades'] + blade_scenario = self.sc_config["blades"] + nacelle_scenario = self.sc_config["nacelle"] + tower_scenario = self.sc_config["blades"] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") - blade_mult = 0. + print( + f"Warning: scenario '{blade_scenario}' not found for category 'blades'." + ) + blade_mult = 0.0 nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") - nacelle_mult = 0. + print( + f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." + ) + nacelle_mult = 0.0 - raw_cost = config.get('project_parameters.turbine_capex', 1300) - blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult - nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult + raw_cost = config.get("project_parameters.turbine_capex", 1300) + blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult + nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = raw_cost * self.turbine_split['tower'] *\ - (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] + tower_tariffs = ( + raw_cost + * self.turbine_split["tower"] + * (1 - self.labor_split["tower"]) + * self.multipliers["tower"]["tariffs"] + ) else: - tower_tariffs = 0. + tower_tariffs = 0.0 tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") - tower_mult = 0. + print( + f"Warning: scenario '{tower_scenario}' not found for category 'tower'." + ) + tower_mult = 0.0 - tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult + tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult - config['project_parameters.turbine_capex'] = sum([ - raw_cost, - blade_adder, - nacelle_adder, - tower_adder, - tower_tariffs - ]) + config["project_parameters.turbine_capex"] = sum( + [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] + ) return config @@ -206,28 +188,29 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config['monopile.unit_cost'] - scenario = self.sc_config['monopile'] + raw_cost = config["monopile.unit_cost"] + scenario = self.sc_config["monopile"] if scenario == "domestic, imported steel": - adder = self.multipliers['monopile']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ - self.multipliers["monopile"]['tariffs'] + adder = self.multipliers["monopile"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["monopile"]) + * self.multipliers["monopile"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'monopile'." + ) + mult = 0.0 adder = raw_cost * mult - config['monopile.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -242,28 +225,29 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config['transition_piece.unit_cost'] - scenario = self.sc_config['transition_piece'] + raw_cost = config["transition_piece.unit_cost"] + scenario = self.sc_config["transition_piece"] if scenario == "domestic, imported steel": - adder = self.multipliers['transition_piece']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ - self.multipliers["transition_piece"]['tariffs'] + adder = self.multipliers["transition_piece"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["transition_piece"]) + * self.multipliers["transition_piece"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'transition_piece'." + ) + mult = 0.0 adder = raw_cost * mult - config['transition_piece.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -278,28 +262,31 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config['offshore_substation_topside.unit_cost'] - scenario = self.sc_config['oss_topside'] + raw_cost = config["offshore_substation_topside.unit_cost"] + scenario = self.sc_config["oss_topside"] if scenario == "domestic, imported steel": - adder = self.multipliers['oss_topside']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ - self.multipliers["oss_topside"]['tariffs'] + adder = self.multipliers["oss_topside"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["oss_topside"]) + * self.multipliers["oss_topside"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'oss_topside'." + ) + mult = 0.0 adder = raw_cost * mult - config['offshore_substation_topside.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["offshore_substation_topside.unit_cost"] = sum( + [raw_cost, adder, tariffs] + ) return config @@ -313,13 +300,15 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['array_cable'] + scenario = self.sc_config["array_cable"] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'array_cable'." + ) + mult = 0.0 - project.system_costs['ArrayCableInstallation'] *= (1 + mult) + project.system_costs["ArrayCableInstallation"] *= 1 + mult return project @@ -332,12 +321,14 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['export_cable'] + scenario = self.sc_config["export_cable"] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'export_cable'." + ) + mult = 0.0 - project.system_costs['ExportCableInstallation'] *= (1 + mult) + project.system_costs["ExportCableInstallation"] *= 1 + mult return project diff --git a/docs/Makefile b/docs/Makefile index 298ea9e2..51285967 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 38ceb207..555a6637 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -sys.path.insert(0, os.path.abspath("..")) - import ORBIT +sys.path.insert(0, os.path.abspath("..")) + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 50478a79..0a3683f9 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW \ No newline at end of file +turbine_rating: 15 # MW diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 75b6fd5c..00a13ba3 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,31 +1,40 @@ -import pandas as pd +import os import math + import numpy as np +import pandas as pd import matplotlib as mpl -import matplotlib.pyplot as plt import matplotlib.text as txt -import os +import matplotlib.pyplot as plt -def mysave(fig, froot, mode='png'): - assert mode in ['png', 'eps', 'pdf', 'all'] + +def mysave(fig, froot, mode="png"): + assert mode in ["png", "eps", "pdf", "all"] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: legs.append(a.get_legend()) + if not addLeg is None: + legs.append(a.get_legend()) ext = [] - if mode == 'png' or mode == 'all': - ext.append('png') - if mode == 'eps': # or mode == 'all': - ext.append('eps') - if mode == 'pdf' or mode == 'all': - ext.append('pdf') + if mode == "png" or mode == "all": + ext.append("png") + if mode == "eps": # or mode == 'all': + ext.append("eps") + if mode == "pdf" or mode == "all": + ext.append("pdf") for sfx in ext: - fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', - dpi=dpiVal, bbox_extra_artists=legs) + fig.savefig( + fileName + "." + sfx, + format=sfx, + pad_inches=padding, + bbox_inches="tight", + dpi=dpiVal, + bbox_extra_artists=legs, + ) titleSize = 24 # 40 #38 @@ -38,32 +47,48 @@ def mysave(fig, froot, mode='png'): linewidth = 3 -def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): - assert type(mode) == type('') - assert mode.lower() in ['save', 'show'], 'Unknown mode' - - def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): - if mode.lower() == 'show': +def myformat( + ax, + linewidth=linewidth, + xticklabel=tickLabelSize, + yticklabel=tickLabelSize, + mode="save", +): + assert type(mode) == type("") + assert mode.lower() in ["save", "show"], "Unknown mode" + + def myformat( + myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel + ): + if mode.lower() == "show": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): + t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_title( + myax.get_title(), size=titleSize + deltaShow, weight="bold" + ) + myax.set_xlabel( + myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" + ) + myax.set_ylabel( + myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" + ) myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -75,27 +100,29 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == 'save': + elif mode.lower() == "save": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize) + for t in leg.get_texts(): + t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') + myax.set_title(myax.get_title(), size=titleSize, weight="bold") + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -108,40 +135,62 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl i.set_linewidth(3) if type(ax) == type([]): - for i in ax: myformat(i) + for i in ax: + myformat(i) else: myformat(ax) + def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax + def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """ Waterfall plot comparing European andUS manufactining costs""" + """Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') + h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) - ax.set_ylabel('Capital Expenditures, $/kW') - ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') - - h[3].set_linestyle('--') + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) + ) + ax.set_ylabel("Capital Expenditures, $/kW") + ax.set_title( + "Comparison of different cost premiums between \nimported and domestically manufactured components" + ) + + h[3].set_linestyle("--") h[3].set_linewidth(1.75) - h[3].set_edgecolor('k') - - ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) - ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) - ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) + h[3].set_edgecolor("k") + + ax.text( + x[1], + 2000, + bar_text["transit"], + horizontalalignment="center", + ) + ax.text( + x[2], + 2000, + bar_text["factory"], + horizontalalignment="center", + ) + ax.text( + x[3], + 2000, + bar_text["margin"], + horizontalalignment="center", + ) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() + def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -150,40 +199,52 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k,v in y.items()]) + y_init = np.sum([v[0] for k, v in y.items()]) - for k,v in y.items(): - y1 = [yi+vi for yi, vi in zip(y0,v)] + for k, v in y.items(): + y1 = [yi + vi for yi, vi in zip(y0, v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, 'w') + ax.plot(x, y1 / y_init, "w") y0 = y1 # Define margin - ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') + ax.fill_between( + x, + y1 / y_init, + np.ones(len(x)), + color=color["Cost margin"], + label="Margin", + ) - final_margin = round( 100* (1 - y1[-1] / y_init), 1) + final_margin = round(100 * (1 - y1[-1] / y_init), 1) - y_margin = ((1 + y1[-1] / y_init) /2) + y_margin = (1 + y1[-1] / y_init) / 2 - margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' + margin_text = ( + " " + + str(final_margin) + + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" + ) right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], 'k') - ax.text(right_bound, y_margin, margin_text, verticalalignment='center') - ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], "k") + ax.text(right_bound, y_margin, margin_text, verticalalignment="center") + ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') - ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') + ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") + ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") - ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') + ax.set_ylabel( + "CapEx breakdown relative to \ncomponents imported from Europe, %" + ) if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index 2b1bdafe..eed5b2c9 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,12 +12,10 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')" + "optional_input": "unit, (optional, default: 'default')", } - output_config = { - "example_output": "unit" - } + output_config = {"example_output": "unit"} def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -45,9 +43,7 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return { - "example_detailed_output": self.result - } + return {"example_detailed_output": self.result} @property def total_cost(self): @@ -60,9 +56,7 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return { - "example_output": self.result - } + return {"example_output": self.result} # === Annotated Example === @@ -75,18 +69,21 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": {"depth": "m"}, # For common inputs that will be shared across many modules, - "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules - "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT - - - + "site": { + "depth": "m" + }, # For common inputs that will be shared across many modules, + "plant": { + "num_turbines": "int" + }, # it's best to look up how the variable is named in existing modules + "turbine": { + "turbine_rating": "MW" + }, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -97,8 +94,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -114,13 +111,18 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above - - - self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library( + config, **kwargs + ) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config( + config + ) # if it hasn't already been and validate the config against '.expected_config' from above + + self._design = self.config.get( + "spar_design", {} + ) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -152,7 +154,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -174,8 +176,10 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get( + "stiffened_column_CR", 3120 + ) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -194,7 +198,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -219,7 +223,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -267,7 +271,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index e15c8156..4cc5fa25 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,7 +11,6 @@ def test_wisdem_monopile_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -23,7 +22,6 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -35,7 +33,6 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index a480e04e..5579f62c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,6 @@ import pytest from marmot import Environment - from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -24,27 +23,23 @@ def pytest_configure(): @pytest.fixture() def env(): - return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): - specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): - specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): - specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -53,7 +48,6 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): - specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -62,19 +56,16 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): - specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): - return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): - yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index 0ce94758..b5f5208b 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,7 +8,6 @@ import pandas as pd import pytest from marmot import le - from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 7320a9f6..9cac3f50 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -58,7 +57,6 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): - project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 915af401..6415118d 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,7 +8,6 @@ import pytest from marmot import Environment - from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -19,7 +18,6 @@ def __init__(self): def test_port_creation(): - env = Environment() port = Port(env) item = SampleItem() @@ -32,7 +30,6 @@ def test_port_creation(): def test_get_item(): - env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index cd1ad5cd..39c42a82 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -209,7 +208,6 @@ def test_correct_turbines(): def test_floating_calculations(): - base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index e1cf3024..ce7a1cd5 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,7 +11,6 @@ import numpy as np import pytest - from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -111,7 +110,6 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): - c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index 9db78fed..dbe18324 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,7 +8,6 @@ from copy import deepcopy import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -104,7 +103,6 @@ def test_design_result(): def test_floating_length_calculations(): - base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 0762b46b..2f69ed18 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,7 +10,6 @@ from itertools import product import pytest - from ORBIT.phases.design import MonopileDesign base = { @@ -37,7 +36,6 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): - config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -61,7 +59,6 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): - test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -80,7 +77,6 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -93,7 +89,6 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): - test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -107,7 +102,6 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index 88a7a747..c59ef535 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT.phases.design import MooringSystemDesign base = { @@ -21,7 +20,6 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): - config = deepcopy(base) config["site"]["depth"] = depth @@ -34,7 +32,6 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): - config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -46,7 +43,6 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): - m = MooringSystemDesign(base) m.run() @@ -75,7 +71,6 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): - config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index b2dd6316..f17b3bd7 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -24,7 +23,6 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -51,7 +49,6 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): - test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -72,7 +69,6 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index 301e5894..d4168fd1 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 7c710fb9..30a134f3 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index 393cf7c1..dbc937c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SparDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index 5a01c14b..f9b1c9a9 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ArrayCableInstallation(config) assert sim.env @@ -37,7 +35,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -53,7 +50,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -72,7 +68,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,7 +84,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -114,7 +108,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): - sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -131,7 +124,6 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -163,7 +155,6 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): - base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -183,7 +174,6 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index 3ab42d15..f3d03350 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -28,7 +27,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -59,7 +57,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index 34669075..e837176c 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -42,7 +40,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -58,7 +55,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -77,7 +73,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -94,7 +89,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -119,7 +113,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -150,7 +143,6 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -182,7 +174,6 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -214,7 +205,6 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index 6811e631..c601a5c6 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = JacketInstallation(config, weather=weather) sim.run() @@ -97,7 +93,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): - base = JacketInstallation(config) base.run() @@ -116,7 +111,6 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): - base = JacketInstallation(config) base.run() @@ -134,7 +128,6 @@ def test_foundation_type(config): def test_kwargs_piles(): - sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -154,7 +147,6 @@ def test_kwargs_piles(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -176,7 +168,6 @@ def test_kwargs_piles(): def test_kwargs_suction(): - config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -197,7 +188,6 @@ def test_kwargs_suction(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 57538063..1759bc3e 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = MonopileInstallation(config, weather=weather) sim.run() @@ -92,7 +88,6 @@ def test_for_complete_logging(weather, config): def test_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -113,7 +108,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -145,7 +139,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -168,7 +161,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -203,7 +195,6 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index bff023f5..2fa11d9e 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -35,7 +34,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -55,7 +53,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 116f7558..3583bbda 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -61,7 +60,6 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): - new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -74,7 +72,6 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -103,7 +100,6 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): - base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -117,7 +113,6 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index be32be3d..30ed4475 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -45,7 +43,6 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): - sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -58,7 +55,6 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -82,7 +78,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -104,7 +99,6 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): - sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -118,7 +112,6 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): - sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -139,7 +132,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -171,7 +163,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -195,7 +186,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 67a28c40..758df489 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -25,7 +24,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -44,7 +42,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index 00fa2b4e..b9a08bac 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -28,7 +27,6 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): - _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -54,7 +52,6 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): - _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -92,7 +89,6 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): - num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index dafad84b..25d7db92 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index e1fc0af7..72619642 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index 85e372c7..ae1c9313 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -51,7 +50,6 @@ def test_full_run_logging(weather): def test_kwargs(): - sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -61,7 +59,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -83,7 +80,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -96,7 +92,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index 6b600eb2..cba9802c 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,7 +9,6 @@ import pandas as pd import pytest from marmot import Environment - from ORBIT.phases.install import InstallPhase @@ -45,7 +44,6 @@ def setup_simulation(self): def test_abstract_methods(): - with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -53,7 +51,6 @@ def test_abstract_methods(): def test_run(): - sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index aac2de9f..0592999a 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): - sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -56,7 +54,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): - sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -80,7 +77,6 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): - sim = TurbineInstallation(config) assert sim.wtiv @@ -97,7 +93,6 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = TurbineInstallation(config, weather=weather) sim.run() @@ -120,7 +115,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): - sim = TurbineInstallation(config) sim.run() @@ -131,7 +125,6 @@ def test_for_complete_installation(config): def test_kwargs(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -153,7 +146,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -175,7 +167,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -200,7 +191,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} @@ -225,7 +215,6 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -245,7 +234,6 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): - vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 055da73d..2042f639 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -33,7 +32,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -56,7 +54,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 209983ac..01e37b7b 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,14 +18,12 @@ def test_good_config(): - config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): - config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -33,7 +31,6 @@ def test_missing_key(): def test_optional(): - config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -41,7 +38,6 @@ def test_optional(): def test_variable_key(): - config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -50,7 +46,6 @@ def test_variable_key(): def test_optional_dict(): - config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index f635f271..ffd84920 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,7 +7,6 @@ import os import pytest - from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -15,7 +14,6 @@ def test_save_and_load_equality(tmp_yaml_del): - save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -23,7 +21,6 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): - config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 059202fb..656db0d8 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,9 +6,8 @@ from copy import deepcopy -from numpy.testing import assert_almost_equal - from ORBIT import ProjectManager +from numpy.testing import assert_almost_equal from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -16,7 +15,6 @@ def test_fixed_phase_cost_passing(): - project = ProjectManager(fixed) project.run() @@ -47,7 +45,6 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): - project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 4d73da75..5d33cfca 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,9 +7,8 @@ import pandas as pd import pytest -from benedict import benedict - from ORBIT import ProjectManager, ParametricManager +from benedict import benedict from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -24,7 +23,6 @@ def test_for_equal_results(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -37,7 +35,6 @@ def test_for_equal_results(): def test_weather(): - without = ParametricManager(complete_project, params, funcs) without.run() @@ -50,7 +47,6 @@ def test_weather(): def test_individual_phase(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -67,7 +63,6 @@ def test_individual_phase(): def test_bad_result_attribute(): - funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -79,7 +74,6 @@ def test_bad_result_attribute(): def test_bad_result_structure(): - funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -91,7 +85,6 @@ def test_bad_result_structure(): def test_product_option(): - params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 7e62a225..9cbf9ad3 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,10 +8,9 @@ import pandas as pd import pytest - from ORBIT import ProjectManager -from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather +from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -26,10 +25,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") + ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): - project = ProjectManager(config, weather=weather) project.run() @@ -47,11 +46,9 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: - assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: - assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -130,7 +127,6 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: - i, expected = test response = TestProjectManager.find_key_match(i) @@ -143,13 +139,11 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: - assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): - config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -169,7 +163,6 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): - config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -233,7 +226,6 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): - config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -283,7 +275,6 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): - # Not a subclass class CustomInstallPhase: pass @@ -305,7 +296,6 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) - # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -318,11 +308,13 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase + assert ( + ProjectManager.find_key_match("CustomInstallPhase") + == CustomInstallPhase + ) def test_custom_design_phases(): - # Not a subclass class CustomDesignPhase: pass @@ -344,7 +336,6 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) - # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -357,11 +348,13 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + assert ( + ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + ) + ### Design Phase Interactions def test_design_phases(): - config_with_design = deepcopy(config) # Add MonopileDesign @@ -386,7 +379,6 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): - # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -467,7 +459,6 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): - incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -477,7 +468,6 @@ def test_incomplete_config(): def test_wrong_phases(): - wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -487,7 +477,6 @@ def test_wrong_phases(): def test_bad_dates(): - bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -500,7 +489,6 @@ def test_bad_dates(): def test_no_defined_start(): - missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -513,7 +501,6 @@ def test_no_defined_start(): def test_circular_dependencies(): - circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -532,7 +519,6 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): - wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -552,7 +538,6 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): - data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -592,7 +577,6 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): - project = ProjectManager(config) project.run() @@ -607,7 +591,6 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): - project = ProjectManager(complete_project) project.run() @@ -633,7 +616,6 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -649,7 +631,6 @@ def test_monthly_expenses(): def test_monthly_revenue(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -666,7 +647,6 @@ def test_monthly_revenue(): def test_cash_flow(): - project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -684,7 +664,6 @@ def test_cash_flow(): def test_npv(): - project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -721,7 +700,6 @@ def test_npv(): def test_soft_costs(): - project = ProjectManager(complete_project) baseline = project.soft_capex @@ -757,7 +735,6 @@ def test_soft_costs(): def test_project_costs(): - project = ProjectManager(complete_project) baseline = project.project_capex @@ -783,7 +760,6 @@ def test_project_costs(): def test_capex_categories(): - project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 64fea1c8..96361d2f 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,4 +1,3 @@ - # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -277,16 +276,18 @@ """ from __future__ import print_function + +import os +import re +import sys +import json +import errno +import subprocess + try: import configparser except ImportError: import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys class VersioneerConfig: @@ -308,11 +309,13 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") + err = ( + "Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND')." + ) raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -325,8 +328,10 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) + print( + "Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py) + ) except NameError: pass return root @@ -348,6 +353,7 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None + cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -372,17 +378,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -390,10 +399,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -418,7 +430,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return stdout, p.returncode -LONG_VERSION_PY['git'] = ''' +LONG_VERSION_PY[ + "git" +] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -993,7 +1007,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1002,7 +1016,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1010,19 +1024,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1037,8 +1058,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1046,10 +1068,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1072,17 +1103,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -1091,10 +1123,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1105,13 +1139,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1167,16 +1203,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1205,11 +1247,17 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1218,8 +1266,9 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps( + versions, sort_keys=True, indent=1, separators=(",", ": ") + ) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1251,8 +1300,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1366,11 +1414,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -1390,9 +1440,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } class VersioneerBadRootError(Exception): @@ -1415,8 +1469,9 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" + assert ( + cfg.versionfile_source is not None + ), "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1470,9 +1525,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } def get_version(): @@ -1521,6 +1580,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1553,14 +1613,17 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join( + self.build_lib, cfg.versionfile_build + ) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1581,17 +1644,21 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if 'py2exe' in sys.modules: # py2exe enabled? + if "py2exe" in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1610,13 +1677,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1643,8 +1714,10 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file( + target_versionfile, self._versioneer_generated_versions + ) + cmds["sdist"] = cmd_sdist return cmds @@ -1699,11 +1772,15 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except ( + EnvironmentError, + configparser.NoSectionError, + configparser.NoOptionError, + ) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print( + "Adding sample versioneer config to setup.cfg", file=sys.stderr + ) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1712,15 +1789,18 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1762,8 +1842,10 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print( + " appending versionfile_source ('%s') to MANIFEST.in" + % cfg.versionfile_source + ) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From d947448c3e719b748a4f65ef2cea5ca329d36731 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 1 Mar 2023 13:46:44 -0700 Subject: [PATCH 11/19] Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" and skip actions This reverts commit 8493b8072754092f7082a3462246be4ef821f14e. --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++------ ORBIT/api/wisdem.py | 1 + ORBIT/config.py | 1 + ORBIT/core/cargo.py | 1 + ORBIT/core/components.py | 1 + ORBIT/core/defaults/__init__.py | 1 + ORBIT/core/environment.py | 2 + ORBIT/core/exceptions.py | 1 + ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 + ORBIT/core/port.py | 1 + ORBIT/core/supply_chain.py | 1 + ORBIT/core/vessel.py | 2 + ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 + ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 8 +- ORBIT/phases/design/export_system_design.py | 2 + ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 + ORBIT/phases/install/cable_install/common.py | 1 + ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 + ORBIT/phases/install/jacket_install/common.py | 1 + .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 + .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 + ORBIT/phases/install/oss_install/common.py | 2 + ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 + .../quayside_assembly_tow/gravity_base.py | 3 + .../install/quayside_assembly_tow/moored.py | 3 + .../scour_protection_install/standard.py | 1 + .../phases/install/turbine_install/common.py | 1 + .../install/turbine_install/standard.py | 4 + ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 ++++------- templates/design_module.py | 74 ++--- tests/api/test_wisdem_api.py | 3 + tests/conftest.py | 9 + tests/core/test_environment.py | 1 + tests/core/test_library.py | 2 + tests/core/test_port.py | 3 + .../phases/design/test_array_system_design.py | 2 + tests/phases/design/test_cable.py | 2 + .../design/test_export_system_design.py | 2 + tests/phases/design/test_monopile_design.py | 6 + .../design/test_mooring_system_design.py | 5 + tests/phases/design/test_oss_design.py | 4 + .../design/test_scour_protection_design.py | 1 + .../design/test_semisubmersible_design.py | 4 + tests/phases/design/test_spar_design.py | 4 + .../cable_install/test_array_install.py | 10 + .../install/cable_install/test_cable_tasks.py | 3 + .../cable_install/test_export_install.py | 10 + .../jacket_install/test_jacket_install.py | 10 + .../monopile_install/test_monopile_install.py | 9 + .../monopile_install/test_monopile_tasks.py | 3 + .../mooring_install/test_mooring_install.py | 5 + .../install/oss_install/test_oss_install.py | 10 + .../install/oss_install/test_oss_tasks.py | 3 + .../quayside_assembly_tow/test_common.py | 4 + .../test_gravity_based.py | 3 + .../quayside_assembly_tow/test_moored.py | 3 + .../test_scour_protection.py | 5 + tests/phases/install/test_install_phase.py | 3 + .../turbine_install/test_turbine_install.py | 12 + .../turbine_install/test_turbine_tasks.py | 3 + tests/phases/test_base.py | 5 + tests/test_config_management.py | 3 + .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 ++- versioneer.py | 298 +++++++----------- 85 files changed, 716 insertions(+), 626 deletions(-) diff --git a/LICENSE b/LICENSE index 1c0c15ea..dbb692d8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index f03f6681..fa1e63bc 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,3 +1,4 @@ + # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -9,11 +10,11 @@ """Git implementation of _version.py.""" +import errno import os import re -import sys -import errno import subprocess +import sys def get_keywords(): @@ -57,20 +58,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -78,13 +76,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -121,22 +116,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -192,7 +181,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -201,7 +190,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -209,26 +198,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -243,9 +225,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -253,19 +234,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -288,18 +260,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -308,12 +279,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -324,15 +293,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -363,7 +330,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -477,13 +445,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -503,13 +469,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} def get_versions(): @@ -523,9 +485,8 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords( - get_keywords(), cfg.tag_prefix, verbose - ) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) except NotThisMethod: pass @@ -534,16 +495,13 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split("/"): + for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -557,10 +515,6 @@ def get_versions(): except NotThisMethod: pass - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 63fd1460..8320e99c 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,6 +7,7 @@ import openmdao.api as om + from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 5a416b43..4a50732d 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,6 +8,7 @@ import yaml from yaml import Dumper + from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index 0f618b4e..d02ab03f 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,6 +6,7 @@ class Cargo(Object): + def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index dec26889..e4e3792c 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,6 +6,7 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 1cc75bae..7df591ec 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,6 +8,7 @@ import os import yaml + from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index bade7d84..4654ec13 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,6 +88,7 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): + if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -138,6 +139,7 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): + if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index ec9fa5d6..8d7d0ca4 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,6 +31,7 @@ def __init__(self, vessel, component): ) def __str__(self): + return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index c8217b15..6f771cc0 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper + from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") - # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index daa4a707..b27a3e78 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -148,6 +149,7 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: + if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -260,13 +262,16 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: + if proposed_deck_space > vessel.storage.max_deck_space: + msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: + msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -327,6 +332,7 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: + vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index c24ccfa6..dbfc152a 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,6 +7,7 @@ import simpy + from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 6f271c9b..0f2f3e1a 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,6 +41,7 @@ def __init__( @process def start(self): + n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index c952e905..88c823a4 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,6 +15,7 @@ WindowNotFound, AgentNotRegistered, ) + from ORBIT.core.components import ( Crane, JackingSys, @@ -85,6 +86,7 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): + duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index ccb0a47d..6aeb5ba1 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,9 +14,10 @@ from itertools import product import numpy as np -import ORBIT import pandas as pd from benedict import benedict + +import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -166,12 +167,14 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): + try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): + idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -202,9 +205,7 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -228,9 +229,7 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -454,6 +453,7 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): + if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,6 +500,7 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): + ret = {} for k, t in self.phase_times.items(): try: @@ -692,6 +693,7 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): + _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -725,6 +727,7 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: + phases = {**phases, **skipped} if not phases: break @@ -823,6 +826,7 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): + if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1100,6 +1104,7 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): + unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1135,6 +1140,7 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): + start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 634b842c..6895400c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,10 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager + class ParametricManager: """Class for configuring parametric ORBIT runs.""" @@ -201,6 +202,7 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): + split = v.split("[") attr = split[0] @@ -296,6 +298,7 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): + if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 1b39d91a..2e9b539d 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,6 +10,7 @@ from copy import deepcopy from benedict import benedict + from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -69,6 +70,7 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): + if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 1b93d209..27343a58 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,6 +11,7 @@ import numpy as np from scipy.optimize import fsolve + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -332,7 +333,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 28b780d9..6fbf911d 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,6 +12,7 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt + from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -383,7 +384,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -578,6 +579,7 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): + ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -742,7 +744,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError @@ -812,6 +814,7 @@ def create_project_csv(self, save_name, folder="cables"): export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): + # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1059,6 +1062,7 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): + self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index bf7af015..6c6ae0a0 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,6 +6,7 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np + from ORBIT.phases.design._cables import CableSystem @@ -212,6 +213,7 @@ def design_result(self): } for name, cable in self.cables.items(): + output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index 082b3a9c..ab1e5349 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,6 +9,7 @@ from math import pi, log from scipy.optimize import fsolve + from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -229,7 +230,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp**2, + "deck_space": D_tp ** 2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -354,7 +355,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -559,7 +560,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 0dcf67d8..383a4924 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index ea72c993..1a2fe071 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,6 +7,7 @@ import numpy as np + from ORBIT.phases.design import DesignPhase @@ -283,7 +284,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass**0.5574 + substructure_pile_mass = 8 * substructure_mass ** 0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index d36b91eb..efa66b4f 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,6 +8,7 @@ from math import ceil import numpy as np + from ORBIT.phases.design import DesignPhase @@ -114,7 +115,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 7bb34217..58404a29 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating**2 + 6.54 * rating + 128.34 + mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index c8b0862e..224c4a5e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,6 +7,7 @@ from numpy import exp, log + from ORBIT.phases.design import DesignPhase @@ -71,7 +72,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -112,7 +113,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -137,7 +138,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index 21120126..d4d8a181 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,6 +10,7 @@ import numpy as np from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -236,6 +237,7 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: + try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -267,6 +269,7 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: + try: length, num_sections, *extra = sections.pop(0) if extra: @@ -288,10 +291,12 @@ def install_array_cables( break for _ in range(num_sections): + try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: + yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index fa0833f2..f2481138 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 55bf7d32..486bc9e7 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,6 +10,7 @@ from math import ceil from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -182,7 +183,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity**0.3549 + 350000 + onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index c4d159d6..97b93c3b 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,6 +12,7 @@ import numpy as np import simpy import pandas as pd + from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 5cd9feb2..4312bfcf 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,6 +5,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 10391d6e..2f8f0c55 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,6 +7,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -110,7 +111,9 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ """ + """ + + """ jacket = Jacket(**self.config["jacket"]) @@ -129,6 +132,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): + items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -369,6 +373,7 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -433,7 +438,9 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index ee1fcb74..04af017a 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,6 +7,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -339,6 +340,7 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 02c7c259..5a204709 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,6 +9,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -105,7 +106,9 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ """ + """ + + """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -116,6 +119,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): + delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -342,6 +346,7 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -403,7 +408,9 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index c4175f28..3b3573b9 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -160,7 +161,9 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: + system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f1c5527b..f90128ac 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -138,6 +139,7 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index a293363d..6580e19a 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,10 +6,11 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, le, process +from marmot import Agent, process, le +from marmot._exceptions import AgentNotRegistered + from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite -from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -143,6 +144,7 @@ def initialize_installation_vessel(self): @property def detailed_output(self): + return {} @@ -173,6 +175,7 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): + start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -193,7 +196,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range(3): + for _ in range (3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 15bcbd79..04038af9 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,6 +8,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -229,7 +230,9 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index a02a3547..4cbd97f6 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,6 +293,7 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -355,6 +357,7 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index 8376b274..c38908b2 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -291,6 +292,7 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -364,6 +366,7 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index db1c8ce6..9dd3ee9a 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,6 +10,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index f65aa7a3..057ff1bd 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index 58e273ab..d23515a1 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,6 +12,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -320,6 +321,7 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -405,7 +407,9 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index 8290eae7..b17e2ae8 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,47 +5,71 @@ from copy import deepcopy - -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager -DEFAULT_MULTIPLIERS = { - "blades": {"domestic": 0.026, "imported": 0.30}, - "nacelle": {"domestic": 0.025, "imported": 0.10}, - "tower": { - "domestic": 0.04, - "imported": 0.20, - "tariffs": 0.25, - }, - "monopile": { - "domestic": 0.085, - "imported": 0.28, - "tariffs": 0.25, - }, - "transition_piece": { - "domestic": 0.169, - "imported": 0.17, - "tariffs": 0.25, - }, - "array_cable": {"domestic": 0.19, "imported": 0.0}, - "export_cable": {"domestic": 0.231, "imported": 0.0}, - "oss_topside": {"domestic": 0.0, "imported": 0.0}, - "oss_substructure": {"domestic": 0.0, "imported": 0.0}, -} -TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} +DEFAULT_MULTIPLIERS = { + "blades": { + "domestic": .026, + "imported": .30 + }, + "nacelle": { + "domestic": .025, + "imported": .10 + }, + "tower": { + "domestic": .04, + "imported": .20, + "tariffs": .25, + }, + "monopile": { + "domestic": .085, + "imported": .28, + "tariffs": .25, + }, + "transition_piece": { + "domestic": .169, + "imported": .17, + "tariffs": .25, + }, + "array_cable": { + "domestic": .19, + "imported": 0. + }, + "export_cable": { + "domestic": .231, + "imported": 0. + }, + "oss_topside": { + "domestic": 0., + "imported": 0. + }, + "oss_substructure": { + "domestic": 0., + "imported": 0. + }, + } + + +TURBINE_CAPEX_SPLIT = { + "blades": 0.135, + "nacelle": 0.274, + "tower": 0.162 +} LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5, + "oss_topside": 0.5 } class SupplyChainManager: + def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -87,17 +111,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config["plant"]) + plant = deepcopy(config['plant']) # Run ProjectManager without install phases to generate design results - install_phases = config["install_phases"] - config["install_phases"] = [] + install_phases = config['install_phases'] + config['install_phases'] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config["plant"] = plant + config['plant'] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -106,8 +130,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config["install_phases"] = install_phases - config["design_phases"] = [] + config['install_phases'] = install_phases + config['design_phases'] = [] return config @@ -130,51 +154,45 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config["blades"] - nacelle_scenario = self.sc_config["nacelle"] - tower_scenario = self.sc_config["blades"] + blade_scenario = self.sc_config['blades'] + nacelle_scenario = self.sc_config['nacelle'] + tower_scenario = self.sc_config['blades'] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print( - f"Warning: scenario '{blade_scenario}' not found for category 'blades'." - ) - blade_mult = 0.0 + print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") + blade_mult = 0. nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print( - f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." - ) - nacelle_mult = 0.0 + print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") + nacelle_mult = 0. - raw_cost = config.get("project_parameters.turbine_capex", 1300) - blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult - nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult + raw_cost = config.get('project_parameters.turbine_capex', 1300) + blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult + nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = ( - raw_cost - * self.turbine_split["tower"] - * (1 - self.labor_split["tower"]) - * self.multipliers["tower"]["tariffs"] - ) + tower_tariffs = raw_cost * self.turbine_split['tower'] *\ + (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] else: - tower_tariffs = 0.0 + tower_tariffs = 0. tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print( - f"Warning: scenario '{tower_scenario}' not found for category 'tower'." - ) - tower_mult = 0.0 + print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") + tower_mult = 0. - tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult + tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult - config["project_parameters.turbine_capex"] = sum( - [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] - ) + config['project_parameters.turbine_capex'] = sum([ + raw_cost, + blade_adder, + nacelle_adder, + tower_adder, + tower_tariffs + ]) return config @@ -188,29 +206,28 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config["monopile.unit_cost"] - scenario = self.sc_config["monopile"] + raw_cost = config['monopile.unit_cost'] + scenario = self.sc_config['monopile'] if scenario == "domestic, imported steel": - adder = self.multipliers["monopile"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["monopile"]) - * self.multipliers["monopile"]["tariffs"] - ) + adder = self.multipliers['monopile']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ + self.multipliers["monopile"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'monopile'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") + mult = 0. adder = raw_cost * mult - config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['monopile.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -225,29 +242,28 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config["transition_piece.unit_cost"] - scenario = self.sc_config["transition_piece"] + raw_cost = config['transition_piece.unit_cost'] + scenario = self.sc_config['transition_piece'] if scenario == "domestic, imported steel": - adder = self.multipliers["transition_piece"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["transition_piece"]) - * self.multipliers["transition_piece"]["tariffs"] - ) + adder = self.multipliers['transition_piece']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ + self.multipliers["transition_piece"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'transition_piece'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") + mult = 0. adder = raw_cost * mult - config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['transition_piece.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -262,31 +278,28 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config["offshore_substation_topside.unit_cost"] - scenario = self.sc_config["oss_topside"] + raw_cost = config['offshore_substation_topside.unit_cost'] + scenario = self.sc_config['oss_topside'] if scenario == "domestic, imported steel": - adder = self.multipliers["oss_topside"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["oss_topside"]) - * self.multipliers["oss_topside"]["tariffs"] - ) + adder = self.multipliers['oss_topside']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ + self.multipliers["oss_topside"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'oss_topside'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") + mult = 0. adder = raw_cost * mult - config["offshore_substation_topside.unit_cost"] = sum( - [raw_cost, adder, tariffs] - ) + config['offshore_substation_topside.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -300,15 +313,13 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["array_cable"] + scenario = self.sc_config['array_cable'] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'array_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") + mult = 0. - project.system_costs["ArrayCableInstallation"] *= 1 + mult + project.system_costs['ArrayCableInstallation'] *= (1 + mult) return project @@ -321,14 +332,12 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["export_cable"] + scenario = self.sc_config['export_cable'] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'export_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") + mult = 0. - project.system_costs["ExportCableInstallation"] *= 1 + mult + project.system_costs['ExportCableInstallation'] *= (1 + mult) return project diff --git a/docs/Makefile b/docs/Makefile index 51285967..298ea9e2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 555a6637..38ceb207 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -import ORBIT - sys.path.insert(0, os.path.abspath("..")) +import ORBIT + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 0a3683f9..50478a79 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW +turbine_rating: 15 # MW \ No newline at end of file diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 00a13ba3..75b6fd5c 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,40 +1,31 @@ -import os +import pandas as pd import math - import numpy as np -import pandas as pd import matplotlib as mpl -import matplotlib.text as txt import matplotlib.pyplot as plt +import matplotlib.text as txt +import os - -def mysave(fig, froot, mode="png"): - assert mode in ["png", "eps", "pdf", "all"] +def mysave(fig, froot, mode='png'): + assert mode in ['png', 'eps', 'pdf', 'all'] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: - legs.append(a.get_legend()) + if not addLeg is None: legs.append(a.get_legend()) ext = [] - if mode == "png" or mode == "all": - ext.append("png") - if mode == "eps": # or mode == 'all': - ext.append("eps") - if mode == "pdf" or mode == "all": - ext.append("pdf") + if mode == 'png' or mode == 'all': + ext.append('png') + if mode == 'eps': # or mode == 'all': + ext.append('eps') + if mode == 'pdf' or mode == 'all': + ext.append('pdf') for sfx in ext: - fig.savefig( - fileName + "." + sfx, - format=sfx, - pad_inches=padding, - bbox_inches="tight", - dpi=dpiVal, - bbox_extra_artists=legs, - ) + fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', + dpi=dpiVal, bbox_extra_artists=legs) titleSize = 24 # 40 #38 @@ -47,48 +38,32 @@ def mysave(fig, froot, mode="png"): linewidth = 3 -def myformat( - ax, - linewidth=linewidth, - xticklabel=tickLabelSize, - yticklabel=tickLabelSize, - mode="save", -): - assert type(mode) == type("") - assert mode.lower() in ["save", "show"], "Unknown mode" - - def myformat( - myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel - ): - if mode.lower() == "show": +def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): + assert type(mode) == type('') + assert mode.lower() in ['save', 'show'], 'Unknown mode' + + def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): + if mode.lower() == 'show': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title( - myax.get_title(), size=titleSize + deltaShow, weight="bold" - ) - myax.set_xlabel( - myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" - ) - myax.set_ylabel( - myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" - ) + myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -100,29 +75,27 @@ def myformat( for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == "save": + elif mode.lower() == 'save': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize) + for t in leg.get_texts(): t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight="bold") - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") + myax.set_title(myax.get_title(), size=titleSize, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -135,62 +108,40 @@ def myformat( i.set_linewidth(3) if type(ax) == type([]): - for i in ax: - myformat(i) + for i in ax: myformat(i) else: myformat(ax) - def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax - def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """Waterfall plot comparing European andUS manufactining costs""" + """ Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") + h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) - ) - ax.set_ylabel("Capital Expenditures, $/kW") - ax.set_title( - "Comparison of different cost premiums between \nimported and domestically manufactured components" - ) - - h[3].set_linestyle("--") + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) + ax.set_ylabel('Capital Expenditures, $/kW') + ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') + + h[3].set_linestyle('--') h[3].set_linewidth(1.75) - h[3].set_edgecolor("k") - - ax.text( - x[1], - 2000, - bar_text["transit"], - horizontalalignment="center", - ) - ax.text( - x[2], - 2000, - bar_text["factory"], - horizontalalignment="center", - ) - ax.text( - x[3], - 2000, - bar_text["margin"], - horizontalalignment="center", - ) + h[3].set_edgecolor('k') + + ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) + ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) + ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() - def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -199,52 +150,40 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k, v in y.items()]) + y_init = np.sum([v[0] for k,v in y.items()]) - for k, v in y.items(): - y1 = [yi + vi for yi, vi in zip(y0, v)] + for k,v in y.items(): + y1 = [yi+vi for yi, vi in zip(y0,v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, "w") + ax.plot(x, y1 / y_init, 'w') y0 = y1 # Define margin - ax.fill_between( - x, - y1 / y_init, - np.ones(len(x)), - color=color["Cost margin"], - label="Margin", - ) + ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') - final_margin = round(100 * (1 - y1[-1] / y_init), 1) + final_margin = round( 100* (1 - y1[-1] / y_init), 1) - y_margin = (1 + y1[-1] / y_init) / 2 + y_margin = ((1 + y1[-1] / y_init) /2) - margin_text = ( - " " - + str(final_margin) - + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" - ) + margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], "k") - ax.text(right_bound, y_margin, margin_text, verticalalignment="center") - ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], 'k') + ax.text(right_bound, y_margin, margin_text, verticalalignment='center') + ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") - ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") + ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') + ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') - ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel( - "CapEx breakdown relative to \ncomponents imported from Europe, %" - ) + ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index eed5b2c9..2b1bdafe 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,10 +12,12 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')", + "optional_input": "unit, (optional, default: 'default')" } - output_config = {"example_output": "unit"} + output_config = { + "example_output": "unit" + } def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -43,7 +45,9 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return {"example_detailed_output": self.result} + return { + "example_detailed_output": self.result + } @property def total_cost(self): @@ -56,7 +60,9 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return {"example_output": self.result} + return { + "example_output": self.result + } # === Annotated Example === @@ -69,21 +75,18 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": { - "depth": "m" - }, # For common inputs that will be shared across many modules, - "plant": { - "num_turbines": "int" - }, # it's best to look up how the variable is named in existing modules - "turbine": { - "turbine_rating": "MW" - }, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + "site": {"depth": "m"}, # For common inputs that will be shared across many modules, + "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules + "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + + + # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -94,8 +97,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -111,18 +114,13 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library( - config, **kwargs - ) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config( - config - ) # if it hasn't already been and validate the config against '.expected_config' from above - - self._design = self.config.get( - "spar_design", {} - ) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above + + + self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -154,7 +152,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -176,10 +174,8 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get( - "stiffened_column_CR", 3120 - ) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -198,7 +194,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -223,7 +219,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -271,7 +267,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index 4cc5fa25..e15c8156 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,6 +11,7 @@ def test_wisdem_monopile_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -22,6 +23,7 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -33,6 +35,7 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index 5579f62c..a480e04e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ import pytest from marmot import Environment + from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -23,23 +24,27 @@ def pytest_configure(): @pytest.fixture() def env(): + return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): + specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): + specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): + specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -48,6 +53,7 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): + specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -56,16 +62,19 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): + specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): + return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): + yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index b5f5208b..0ce94758 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,6 +8,7 @@ import pandas as pd import pytest from marmot import le + from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 9cac3f50..7320a9f6 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -57,6 +58,7 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): + project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 6415118d..915af401 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,6 +8,7 @@ import pytest from marmot import Environment + from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -18,6 +19,7 @@ def __init__(self): def test_port_creation(): + env = Environment() port = Port(env) item = SampleItem() @@ -30,6 +32,7 @@ def test_port_creation(): def test_get_item(): + env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index 39c42a82..cd1ad5cd 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -208,6 +209,7 @@ def test_correct_turbines(): def test_floating_calculations(): + base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index ce7a1cd5..e1cf3024 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,6 +11,7 @@ import numpy as np import pytest + from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -110,6 +111,7 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): + c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index dbe18324..9db78fed 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,6 +8,7 @@ from copy import deepcopy import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -103,6 +104,7 @@ def test_design_result(): def test_floating_length_calculations(): + base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 2f69ed18..0762b46b 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,6 +10,7 @@ from itertools import product import pytest + from ORBIT.phases.design import MonopileDesign base = { @@ -36,6 +37,7 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): + config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -59,6 +61,7 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): + test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -77,6 +80,7 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -89,6 +93,7 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): + test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -102,6 +107,7 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index c59ef535..88a7a747 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT.phases.design import MooringSystemDesign base = { @@ -20,6 +21,7 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): + config = deepcopy(base) config["site"]["depth"] = depth @@ -32,6 +34,7 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): + config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -43,6 +46,7 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): + m = MooringSystemDesign(base) m.run() @@ -71,6 +75,7 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): + config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index f17b3bd7..b2dd6316 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -23,6 +24,7 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -49,6 +51,7 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): + test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -69,6 +72,7 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index d4168fd1..301e5894 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 30a134f3..7c710fb9 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index dbc937c1..393cf7c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SparDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index f9b1c9a9..5a01c14b 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ArrayCableInstallation(config) assert sim.env @@ -35,6 +37,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -50,6 +53,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -68,6 +72,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -84,6 +89,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -108,6 +114,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): + sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -124,6 +131,7 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -155,6 +163,7 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): + base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -174,6 +183,7 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index f3d03350..3ab42d15 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -27,6 +28,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -57,6 +59,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index e837176c..34669075 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -40,6 +42,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -55,6 +58,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -73,6 +77,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,6 +94,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -113,6 +119,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -143,6 +150,7 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -174,6 +182,7 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -205,6 +214,7 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index c601a5c6..6811e631 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = JacketInstallation(config, weather=weather) sim.run() @@ -93,6 +97,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): + base = JacketInstallation(config) base.run() @@ -111,6 +116,7 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): + base = JacketInstallation(config) base.run() @@ -128,6 +134,7 @@ def test_foundation_type(config): def test_kwargs_piles(): + sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -147,6 +154,7 @@ def test_kwargs_piles(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -168,6 +176,7 @@ def test_kwargs_piles(): def test_kwargs_suction(): + config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -188,6 +197,7 @@ def test_kwargs_suction(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 1759bc3e..57538063 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = MonopileInstallation(config, weather=weather) sim.run() @@ -88,6 +92,7 @@ def test_for_complete_logging(weather, config): def test_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -108,6 +113,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -139,6 +145,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -161,6 +168,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -195,6 +203,7 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index 2fa11d9e..bff023f5 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -34,6 +35,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -53,6 +55,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 3583bbda..116f7558 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -60,6 +61,7 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): + new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -72,6 +74,7 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -100,6 +103,7 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): + base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -113,6 +117,7 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index 30ed4475..be32be3d 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -43,6 +45,7 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): + sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -55,6 +58,7 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -78,6 +82,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -99,6 +104,7 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): + sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -112,6 +118,7 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): + sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -132,6 +139,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -163,6 +171,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -186,6 +195,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 758df489..67a28c40 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -24,6 +25,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -42,6 +44,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index b9a08bac..00fa2b4e 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -27,6 +28,7 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): + _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -52,6 +54,7 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): + _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -89,6 +92,7 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): + num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index 25d7db92..dafad84b 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index 72619642..e1fc0af7 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index ae1c9313..85e372c7 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -50,6 +51,7 @@ def test_full_run_logging(weather): def test_kwargs(): + sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -59,6 +61,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -80,6 +83,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -92,6 +96,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index cba9802c..6b600eb2 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,6 +9,7 @@ import pandas as pd import pytest from marmot import Environment + from ORBIT.phases.install import InstallPhase @@ -44,6 +45,7 @@ def setup_simulation(self): def test_abstract_methods(): + with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -51,6 +53,7 @@ def test_abstract_methods(): def test_run(): + sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index 0592999a..aac2de9f 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): + sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -54,6 +56,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): + sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -77,6 +80,7 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): + sim = TurbineInstallation(config) assert sim.wtiv @@ -93,6 +97,7 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = TurbineInstallation(config, weather=weather) sim.run() @@ -115,6 +120,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): + sim = TurbineInstallation(config) sim.run() @@ -125,6 +131,7 @@ def test_for_complete_installation(config): def test_kwargs(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -146,6 +153,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -167,6 +175,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -191,6 +200,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} @@ -215,6 +225,7 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -234,6 +245,7 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): + vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 2042f639..055da73d 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -32,6 +33,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -54,6 +56,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 01e37b7b..209983ac 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,12 +18,14 @@ def test_good_config(): + config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): + config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -31,6 +33,7 @@ def test_missing_key(): def test_optional(): + config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -38,6 +41,7 @@ def test_optional(): def test_variable_key(): + config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -46,6 +50,7 @@ def test_variable_key(): def test_optional_dict(): + config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index ffd84920..f635f271 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,6 +7,7 @@ import os import pytest + from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -14,6 +15,7 @@ def test_save_and_load_equality(tmp_yaml_del): + save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -21,6 +23,7 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): + config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 656db0d8..059202fb 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,8 +6,9 @@ from copy import deepcopy -from ORBIT import ProjectManager from numpy.testing import assert_almost_equal + +from ORBIT import ProjectManager from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -15,6 +16,7 @@ def test_fixed_phase_cost_passing(): + project = ProjectManager(fixed) project.run() @@ -45,6 +47,7 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): + project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 5d33cfca..4d73da75 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,8 +7,9 @@ import pandas as pd import pytest -from ORBIT import ProjectManager, ParametricManager from benedict import benedict + +from ORBIT import ProjectManager, ParametricManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -23,6 +24,7 @@ def test_for_equal_results(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -35,6 +37,7 @@ def test_for_equal_results(): def test_weather(): + without = ParametricManager(complete_project, params, funcs) without.run() @@ -47,6 +50,7 @@ def test_weather(): def test_individual_phase(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -63,6 +67,7 @@ def test_individual_phase(): def test_bad_result_attribute(): + funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -74,6 +79,7 @@ def test_bad_result_attribute(): def test_bad_result_structure(): + funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -85,6 +91,7 @@ def test_bad_result_structure(): def test_product_option(): + params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 9cbf9ad3..7e62a225 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,9 +8,10 @@ import pandas as pd import pytest + from ORBIT import ProjectManager +from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather -from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -25,10 +26,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") - ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): + project = ProjectManager(config, weather=weather) project.run() @@ -46,9 +47,11 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: + assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: + assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -127,6 +130,7 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: + i, expected = test response = TestProjectManager.find_key_match(i) @@ -139,11 +143,13 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: + assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): + config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -163,6 +169,7 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): + config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -226,6 +233,7 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): + config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -275,6 +283,7 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): + # Not a subclass class CustomInstallPhase: pass @@ -296,6 +305,7 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) + # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -308,13 +318,11 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ( - ProjectManager.find_key_match("CustomInstallPhase") - == CustomInstallPhase - ) + assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase def test_custom_design_phases(): + # Not a subclass class CustomDesignPhase: pass @@ -336,6 +344,7 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) + # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -348,13 +357,11 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ( - ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase - ) - + assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase ### Design Phase Interactions def test_design_phases(): + config_with_design = deepcopy(config) # Add MonopileDesign @@ -379,6 +386,7 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): + # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -459,6 +467,7 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): + incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -468,6 +477,7 @@ def test_incomplete_config(): def test_wrong_phases(): + wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -477,6 +487,7 @@ def test_wrong_phases(): def test_bad_dates(): + bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -489,6 +500,7 @@ def test_bad_dates(): def test_no_defined_start(): + missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -501,6 +513,7 @@ def test_no_defined_start(): def test_circular_dependencies(): + circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -519,6 +532,7 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): + wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -538,6 +552,7 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): + data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -577,6 +592,7 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): + project = ProjectManager(config) project.run() @@ -591,6 +607,7 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): + project = ProjectManager(complete_project) project.run() @@ -616,6 +633,7 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -631,6 +649,7 @@ def test_monthly_expenses(): def test_monthly_revenue(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -647,6 +666,7 @@ def test_monthly_revenue(): def test_cash_flow(): + project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -664,6 +684,7 @@ def test_cash_flow(): def test_npv(): + project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -700,6 +721,7 @@ def test_npv(): def test_soft_costs(): + project = ProjectManager(complete_project) baseline = project.soft_capex @@ -735,6 +757,7 @@ def test_soft_costs(): def test_project_costs(): + project = ProjectManager(complete_project) baseline = project.project_capex @@ -760,6 +783,7 @@ def test_project_costs(): def test_capex_categories(): + project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 96361d2f..64fea1c8 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,3 +1,4 @@ + # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -276,18 +277,16 @@ """ from __future__ import print_function - -import os -import re -import sys -import json -import errno -import subprocess - try: import configparser except ImportError: import ConfigParser as configparser +import errno +import json +import os +import re +import subprocess +import sys class VersioneerConfig: @@ -309,13 +308,11 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ( - "Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND')." - ) + err = ("Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -328,10 +325,8 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print( - "Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py) - ) + print("Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py)) except NameError: pass return root @@ -353,7 +348,6 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None - cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -378,20 +372,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -399,13 +390,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -430,9 +418,7 @@ def run_command( return stdout, p.returncode -LONG_VERSION_PY[ - "git" -] = ''' +LONG_VERSION_PY['git'] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -1007,7 +993,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1016,7 +1002,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1024,26 +1010,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -1058,9 +1037,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1068,19 +1046,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1103,18 +1072,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -1123,12 +1091,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1139,15 +1105,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1203,22 +1167,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1247,17 +1205,11 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search( - r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: - mo = re.search( - r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1266,9 +1218,8 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps( - versions, sort_keys=True, indent=1, separators=(",", ": ") - ) + contents = json.dumps(versions, sort_keys=True, + indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1300,7 +1251,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1414,13 +1366,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -1440,13 +1390,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} class VersioneerBadRootError(Exception): @@ -1469,9 +1415,8 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert ( - cfg.versionfile_source is not None - ), "please set versioneer.versionfile_source" + assert cfg.versionfile_source is not None, \ + "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1525,13 +1470,9 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, "error": "unable to compute version", + "date": None} def get_version(): @@ -1580,7 +1521,6 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1613,17 +1553,14 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join( - self.build_lib, cfg.versionfile_build - ) + target_versionfile = os.path.join(self.build_lib, + cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1644,21 +1581,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if "py2exe" in sys.modules: # py2exe enabled? + if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1677,17 +1610,13 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1714,10 +1643,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file( - target_versionfile, self._versioneer_generated_versions - ) - + write_to_version_file(target_versionfile, + self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds @@ -1772,15 +1699,11 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except ( - EnvironmentError, - configparser.NoSectionError, - configparser.NoOptionError, - ) as e: + except (EnvironmentError, configparser.NoSectionError, + configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print( - "Adding sample versioneer config to setup.cfg", file=sys.stderr - ) + print("Adding sample versioneer config to setup.cfg", + file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1789,18 +1712,15 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") + f.write(LONG % {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), + "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1842,10 +1762,8 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print( - " appending versionfile_source ('%s') to MANIFEST.in" - % cfg.versionfile_source - ) + print(" appending versionfile_source ('%s') to MANIFEST.in" % + cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From b1e53ed8676aaa00476d477064aca7922c3aa7b9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:48:00 +0000 Subject: [PATCH 12/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++++---- ORBIT/api/wisdem.py | 1 - ORBIT/config.py | 1 - ORBIT/core/cargo.py | 1 - ORBIT/core/components.py | 1 - ORBIT/core/defaults/__init__.py | 1 - ORBIT/core/environment.py | 2 - ORBIT/core/exceptions.py | 1 - ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 - ORBIT/core/port.py | 1 - ORBIT/core/supply_chain.py | 1 - ORBIT/core/vessel.py | 2 - ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 - ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 8 +- ORBIT/phases/design/export_system_design.py | 2 - ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 - ORBIT/phases/install/cable_install/common.py | 1 - ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 - ORBIT/phases/install/jacket_install/common.py | 1 - .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 - .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 - ORBIT/phases/install/oss_install/common.py | 2 - ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 - .../quayside_assembly_tow/gravity_base.py | 3 - .../install/quayside_assembly_tow/moored.py | 3 - .../scour_protection_install/standard.py | 1 - .../phases/install/turbine_install/common.py | 1 - .../install/turbine_install/standard.py | 4 - ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 +++++++---- templates/design_module.py | 74 +++-- tests/api/test_wisdem_api.py | 3 - tests/conftest.py | 9 - tests/core/test_environment.py | 1 - tests/core/test_library.py | 2 - tests/core/test_port.py | 3 - .../phases/design/test_array_system_design.py | 2 - tests/phases/design/test_cable.py | 2 - .../design/test_export_system_design.py | 2 - tests/phases/design/test_monopile_design.py | 6 - .../design/test_mooring_system_design.py | 5 - tests/phases/design/test_oss_design.py | 4 - .../design/test_scour_protection_design.py | 1 - .../design/test_semisubmersible_design.py | 4 - tests/phases/design/test_spar_design.py | 4 - .../cable_install/test_array_install.py | 10 - .../install/cable_install/test_cable_tasks.py | 3 - .../cable_install/test_export_install.py | 10 - .../jacket_install/test_jacket_install.py | 10 - .../monopile_install/test_monopile_install.py | 9 - .../monopile_install/test_monopile_tasks.py | 3 - .../mooring_install/test_mooring_install.py | 5 - .../install/oss_install/test_oss_install.py | 10 - .../install/oss_install/test_oss_tasks.py | 3 - .../quayside_assembly_tow/test_common.py | 4 - .../test_gravity_based.py | 3 - .../quayside_assembly_tow/test_moored.py | 3 - .../test_scour_protection.py | 5 - tests/phases/install/test_install_phase.py | 3 - .../turbine_install/test_turbine_install.py | 12 - .../turbine_install/test_turbine_tasks.py | 3 - tests/phases/test_base.py | 5 - tests/test_config_management.py | 3 - .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 +-- versioneer.py | 298 +++++++++++------- 85 files changed, 626 insertions(+), 716 deletions(-) diff --git a/LICENSE b/LICENSE index dbb692d8..1c0c15ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index fa1e63bc..f03f6681 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,4 +1,3 @@ - # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -10,11 +9,11 @@ """Git implementation of _version.py.""" -import errno import os import re -import subprocess import sys +import errno +import subprocess def get_keywords(): @@ -58,17 +57,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -76,10 +78,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -116,16 +121,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -181,7 +192,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -190,7 +201,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -198,19 +209,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -225,8 +243,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -234,10 +253,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -260,17 +288,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -279,10 +308,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -293,13 +324,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -330,8 +363,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -445,11 +477,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -469,9 +503,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } def get_versions(): @@ -485,8 +523,9 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) + return git_versions_from_keywords( + get_keywords(), cfg.tag_prefix, verbose + ) except NotThisMethod: pass @@ -495,13 +534,16 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): + for i in cfg.versionfile_source.split("/"): root = os.path.dirname(root) except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None, + } try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -515,6 +557,10 @@ def get_versions(): except NotThisMethod: pass - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 8320e99c..63fd1460 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,7 +7,6 @@ import openmdao.api as om - from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 4a50732d..5a416b43 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,7 +8,6 @@ import yaml from yaml import Dumper - from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index d02ab03f..0f618b4e 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,7 +6,6 @@ class Cargo(Object): - def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index e4e3792c..dec26889 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,7 +6,6 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 7df591ec..1cc75bae 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,7 +8,6 @@ import os import yaml - from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index 4654ec13..bade7d84 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,7 +88,6 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): - if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -139,7 +138,6 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): - if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index 8d7d0ca4..ec9fa5d6 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,7 +31,6 @@ def __init__(self, vessel, component): ) def __str__(self): - return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index 6f771cc0..c8217b15 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper - from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") + # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index b27a3e78..daa4a707 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -149,7 +148,6 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: - if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -262,16 +260,13 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: - if proposed_deck_space > vessel.storage.max_deck_space: - msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: - msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -332,7 +327,6 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: - vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index dbfc152a..c24ccfa6 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,7 +7,6 @@ import simpy - from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 0f2f3e1a..6f271c9b 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,7 +41,6 @@ def __init__( @process def start(self): - n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index 88c823a4..c952e905 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,7 +15,6 @@ WindowNotFound, AgentNotRegistered, ) - from ORBIT.core.components import ( Crane, JackingSys, @@ -86,7 +85,6 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): - duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index 6aeb5ba1..ccb0a47d 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,10 +14,9 @@ from itertools import product import numpy as np +import ORBIT import pandas as pd from benedict import benedict - -import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -167,14 +166,12 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): - try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): - idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -205,7 +202,9 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -229,7 +228,9 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError(f"A phase with name '{phase.__name__}' already exists.") + raise ValueError( + f"A phase with name '{phase.__name__}' already exists." + ) if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -453,7 +454,6 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): - if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,7 +500,6 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): - ret = {} for k, t in self.phase_times.items(): try: @@ -693,7 +692,6 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): - _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -727,7 +725,6 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: - phases = {**phases, **skipped} if not phases: break @@ -826,7 +823,6 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): - if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1104,7 +1100,6 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): - unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1140,7 +1135,6 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): - start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 6895400c..634b842c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,8 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from benedict import benedict - from ORBIT import ProjectManager +from benedict import benedict class ParametricManager: @@ -202,7 +201,6 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): - split = v.split("[") attr = split[0] @@ -298,7 +296,6 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): - if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 2e9b539d..1b39d91a 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,7 +10,6 @@ from copy import deepcopy from benedict import benedict - from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -70,7 +69,6 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): - if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 27343a58..1b93d209 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,7 +11,6 @@ import numpy as np from scipy.optimize import fsolve - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -333,7 +332,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 6fbf911d..28b780d9 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,7 +12,6 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt - from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -384,7 +383,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -579,7 +578,6 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): - ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -744,7 +742,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError @@ -814,7 +812,6 @@ def create_project_csv(self, save_name, folder="cables"): export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): - # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1062,7 +1059,6 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): - self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index 6c6ae0a0..bf7af015 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,7 +6,6 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np - from ORBIT.phases.design._cables import CableSystem @@ -213,7 +212,6 @@ def design_result(self): } for name, cable in self.cables.items(): - output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index ab1e5349..082b3a9c 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,7 +9,6 @@ from math import pi, log from scipy.optimize import fsolve - from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -230,7 +229,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp ** 2, + "deck_space": D_tp**2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -355,7 +354,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -560,7 +559,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 383a4924..0dcf67d8 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index 1a2fe071..ea72c993 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,7 +7,6 @@ import numpy as np - from ORBIT.phases.design import DesignPhase @@ -284,7 +283,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass ** 0.5574 + substructure_pile_mass = 8 * substructure_mass**0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index efa66b4f..d36b91eb 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,7 +8,6 @@ from math import ceil import numpy as np - from ORBIT.phases.design import DesignPhase @@ -115,7 +114,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 58404a29..7bb34217 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 + mass = -0.153 * rating**2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index 224c4a5e..c8b0862e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,7 +7,6 @@ from numpy import exp, log - from ORBIT.phases.design import DesignPhase @@ -72,7 +71,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -113,7 +112,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -138,7 +137,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index d4d8a181..21120126 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,7 +10,6 @@ import numpy as np from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -237,7 +236,6 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: - try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -269,7 +267,6 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: - try: length, num_sections, *extra = sections.pop(0) if extra: @@ -291,12 +288,10 @@ def install_array_cables( break for _ in range(num_sections): - try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: - yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index f2481138..fa0833f2 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 486bc9e7..55bf7d32 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,7 +10,6 @@ from math import ceil from marmot import process - from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -183,7 +182,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 + onshore_misc_cost = 11795 * capacity**0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index 97b93c3b..c4d159d6 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,7 +12,6 @@ import numpy as np import simpy import pandas as pd - from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 4312bfcf..5cd9feb2 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,7 +5,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 2f8f0c55..10391d6e 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,7 +7,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -111,9 +110,7 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ - - """ + """ """ jacket = Jacket(**self.config["jacket"]) @@ -132,7 +129,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): - items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -373,7 +369,6 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -438,9 +433,7 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index 04af017a..ee1fcb74 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,7 +7,6 @@ from marmot import false, process - from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -340,7 +339,6 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 5a204709..02c7c259 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,7 +9,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -106,9 +105,7 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ - - """ + """ """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -119,7 +116,6 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): - delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -346,7 +342,6 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -408,9 +403,7 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index 3b3573b9..c4175f28 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -161,9 +160,7 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: - if vessel.storage.items: - system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f90128ac..f1c5527b 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -139,7 +138,6 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": - yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index 6580e19a..a293363d 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,11 +6,10 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, process, le -from marmot._exceptions import AgentNotRegistered - +from marmot import Agent, le, process from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite +from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -144,7 +143,6 @@ def initialize_installation_vessel(self): @property def detailed_output(self): - return {} @@ -175,7 +173,6 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): - start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -196,7 +193,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range (3): + for _ in range(3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 04038af9..15bcbd79 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,7 +8,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -230,9 +229,7 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: - if queue.vessel: - # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index 4cbd97f6..a02a3547 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -293,7 +292,6 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -357,7 +355,6 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index c38908b2..8376b274 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,7 +8,6 @@ import simpy from marmot import le, process - from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,7 +291,6 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: - start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -366,7 +364,6 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: - start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index 9dd3ee9a..db1c8ce6 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,7 +10,6 @@ import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index 057ff1bd..f65aa7a3 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,7 +7,6 @@ from marmot import process - from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index d23515a1..58e273ab 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,7 +12,6 @@ import numpy as np import simpy from marmot import process - from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -321,7 +320,6 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: - if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -407,9 +405,7 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: - if queue.vessel: - # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index b17e2ae8..8290eae7 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,71 +5,47 @@ from copy import deepcopy -from benedict import benedict -from ORBIT import ProjectManager - +from ORBIT import ProjectManager +from benedict import benedict DEFAULT_MULTIPLIERS = { - "blades": { - "domestic": .026, - "imported": .30 - }, - "nacelle": { - "domestic": .025, - "imported": .10 - }, - "tower": { - "domestic": .04, - "imported": .20, - "tariffs": .25, - }, - "monopile": { - "domestic": .085, - "imported": .28, - "tariffs": .25, - }, - "transition_piece": { - "domestic": .169, - "imported": .17, - "tariffs": .25, - }, - "array_cable": { - "domestic": .19, - "imported": 0. - }, - "export_cable": { - "domestic": .231, - "imported": 0. - }, - "oss_topside": { - "domestic": 0., - "imported": 0. - }, - "oss_substructure": { - "domestic": 0., - "imported": 0. - }, - } - - -TURBINE_CAPEX_SPLIT = { - "blades": 0.135, - "nacelle": 0.274, - "tower": 0.162 + "blades": {"domestic": 0.026, "imported": 0.30}, + "nacelle": {"domestic": 0.025, "imported": 0.10}, + "tower": { + "domestic": 0.04, + "imported": 0.20, + "tariffs": 0.25, + }, + "monopile": { + "domestic": 0.085, + "imported": 0.28, + "tariffs": 0.25, + }, + "transition_piece": { + "domestic": 0.169, + "imported": 0.17, + "tariffs": 0.25, + }, + "array_cable": {"domestic": 0.19, "imported": 0.0}, + "export_cable": {"domestic": 0.231, "imported": 0.0}, + "oss_topside": {"domestic": 0.0, "imported": 0.0}, + "oss_substructure": {"domestic": 0.0, "imported": 0.0}, } +TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} + + LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5 + "oss_topside": 0.5, } class SupplyChainManager: - def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -111,17 +87,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config['plant']) + plant = deepcopy(config["plant"]) # Run ProjectManager without install phases to generate design results - install_phases = config['install_phases'] - config['install_phases'] = [] + install_phases = config["install_phases"] + config["install_phases"] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config['plant'] = plant + config["plant"] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -130,8 +106,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config['install_phases'] = install_phases - config['design_phases'] = [] + config["install_phases"] = install_phases + config["design_phases"] = [] return config @@ -154,45 +130,51 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config['blades'] - nacelle_scenario = self.sc_config['nacelle'] - tower_scenario = self.sc_config['blades'] + blade_scenario = self.sc_config["blades"] + nacelle_scenario = self.sc_config["nacelle"] + tower_scenario = self.sc_config["blades"] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") - blade_mult = 0. + print( + f"Warning: scenario '{blade_scenario}' not found for category 'blades'." + ) + blade_mult = 0.0 nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") - nacelle_mult = 0. + print( + f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." + ) + nacelle_mult = 0.0 - raw_cost = config.get('project_parameters.turbine_capex', 1300) - blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult - nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult + raw_cost = config.get("project_parameters.turbine_capex", 1300) + blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult + nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = raw_cost * self.turbine_split['tower'] *\ - (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] + tower_tariffs = ( + raw_cost + * self.turbine_split["tower"] + * (1 - self.labor_split["tower"]) + * self.multipliers["tower"]["tariffs"] + ) else: - tower_tariffs = 0. + tower_tariffs = 0.0 tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") - tower_mult = 0. + print( + f"Warning: scenario '{tower_scenario}' not found for category 'tower'." + ) + tower_mult = 0.0 - tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult + tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult - config['project_parameters.turbine_capex'] = sum([ - raw_cost, - blade_adder, - nacelle_adder, - tower_adder, - tower_tariffs - ]) + config["project_parameters.turbine_capex"] = sum( + [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] + ) return config @@ -206,28 +188,29 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config['monopile.unit_cost'] - scenario = self.sc_config['monopile'] + raw_cost = config["monopile.unit_cost"] + scenario = self.sc_config["monopile"] if scenario == "domestic, imported steel": - adder = self.multipliers['monopile']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ - self.multipliers["monopile"]['tariffs'] + adder = self.multipliers["monopile"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["monopile"]) + * self.multipliers["monopile"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'monopile'." + ) + mult = 0.0 adder = raw_cost * mult - config['monopile.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -242,28 +225,29 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config['transition_piece.unit_cost'] - scenario = self.sc_config['transition_piece'] + raw_cost = config["transition_piece.unit_cost"] + scenario = self.sc_config["transition_piece"] if scenario == "domestic, imported steel": - adder = self.multipliers['transition_piece']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ - self.multipliers["transition_piece"]['tariffs'] + adder = self.multipliers["transition_piece"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["transition_piece"]) + * self.multipliers["transition_piece"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'transition_piece'." + ) + mult = 0.0 adder = raw_cost * mult - config['transition_piece.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) return config @@ -278,28 +262,31 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config['offshore_substation_topside.unit_cost'] - scenario = self.sc_config['oss_topside'] + raw_cost = config["offshore_substation_topside.unit_cost"] + scenario = self.sc_config["oss_topside"] if scenario == "domestic, imported steel": - adder = self.multipliers['oss_topside']['domestic'] * raw_cost - tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ - self.multipliers["oss_topside"]['tariffs'] + adder = self.multipliers["oss_topside"]["domestic"] * raw_cost + tariffs = ( + raw_cost + * (1 - self.labor_split["oss_topside"]) + * self.multipliers["oss_topside"]["tariffs"] + ) else: - tariffs = 0. + tariffs = 0.0 mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'oss_topside'." + ) + mult = 0.0 adder = raw_cost * mult - config['offshore_substation_topside.unit_cost'] = sum([ - raw_cost, - adder, - tariffs - ]) + config["offshore_substation_topside.unit_cost"] = sum( + [raw_cost, adder, tariffs] + ) return config @@ -313,13 +300,15 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['array_cable'] + scenario = self.sc_config["array_cable"] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'array_cable'." + ) + mult = 0.0 - project.system_costs['ArrayCableInstallation'] *= (1 + mult) + project.system_costs["ArrayCableInstallation"] *= 1 + mult return project @@ -332,12 +321,14 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config['export_cable'] + scenario = self.sc_config["export_cable"] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") - mult = 0. + print( + f"Warning: scenario '{scenario}' not found for category 'export_cable'." + ) + mult = 0.0 - project.system_costs['ExportCableInstallation'] *= (1 + mult) + project.system_costs["ExportCableInstallation"] *= 1 + mult return project diff --git a/docs/Makefile b/docs/Makefile index 298ea9e2..51285967 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py index 38ceb207..555a6637 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -sys.path.insert(0, os.path.abspath("..")) - import ORBIT +sys.path.insert(0, os.path.abspath("..")) + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 50478a79..0a3683f9 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW \ No newline at end of file +turbine_rating: 15 # MW diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 75b6fd5c..00a13ba3 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,31 +1,40 @@ -import pandas as pd +import os import math + import numpy as np +import pandas as pd import matplotlib as mpl -import matplotlib.pyplot as plt import matplotlib.text as txt -import os +import matplotlib.pyplot as plt -def mysave(fig, froot, mode='png'): - assert mode in ['png', 'eps', 'pdf', 'all'] + +def mysave(fig, froot, mode="png"): + assert mode in ["png", "eps", "pdf", "all"] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: legs.append(a.get_legend()) + if not addLeg is None: + legs.append(a.get_legend()) ext = [] - if mode == 'png' or mode == 'all': - ext.append('png') - if mode == 'eps': # or mode == 'all': - ext.append('eps') - if mode == 'pdf' or mode == 'all': - ext.append('pdf') + if mode == "png" or mode == "all": + ext.append("png") + if mode == "eps": # or mode == 'all': + ext.append("eps") + if mode == "pdf" or mode == "all": + ext.append("pdf") for sfx in ext: - fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', - dpi=dpiVal, bbox_extra_artists=legs) + fig.savefig( + fileName + "." + sfx, + format=sfx, + pad_inches=padding, + bbox_inches="tight", + dpi=dpiVal, + bbox_extra_artists=legs, + ) titleSize = 24 # 40 #38 @@ -38,32 +47,48 @@ def mysave(fig, froot, mode='png'): linewidth = 3 -def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): - assert type(mode) == type('') - assert mode.lower() in ['save', 'show'], 'Unknown mode' - - def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): - if mode.lower() == 'show': +def myformat( + ax, + linewidth=linewidth, + xticklabel=tickLabelSize, + yticklabel=tickLabelSize, + mode="save", +): + assert type(mode) == type("") + assert mode.lower() in ["save", "show"], "Unknown mode" + + def myformat( + myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel + ): + if mode.lower() == "show": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): + t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_title( + myax.get_title(), size=titleSize + deltaShow, weight="bold" + ) + myax.set_xlabel( + myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" + ) + myax.set_ylabel( + myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" + ) myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -75,27 +100,29 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == 'save': + elif mode.lower() == "save": for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == 'D': continue # Don't modify baseline diamond + if i.get_marker() == "D": + continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): t.set_fontsize(legendSize) + for t in leg.get_texts(): + t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight='bold') - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') + myax.set_title(myax.get_title(), size=titleSize, weight="bold") + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -108,40 +135,62 @@ def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=ytickl i.set_linewidth(3) if type(ax) == type([]): - for i in ax: myformat(i) + for i in ax: + myformat(i) else: myformat(ax) + def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax + def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """ Waterfall plot comparing European andUS manufactining costs""" + """Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') + h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) - ax.set_ylabel('Capital Expenditures, $/kW') - ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') - - h[3].set_linestyle('--') + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) + ) + ax.set_ylabel("Capital Expenditures, $/kW") + ax.set_title( + "Comparison of different cost premiums between \nimported and domestically manufactured components" + ) + + h[3].set_linestyle("--") h[3].set_linewidth(1.75) - h[3].set_edgecolor('k') - - ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) - ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) - ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) + h[3].set_edgecolor("k") + + ax.text( + x[1], + 2000, + bar_text["transit"], + horizontalalignment="center", + ) + ax.text( + x[2], + 2000, + bar_text["factory"], + horizontalalignment="center", + ) + ax.text( + x[3], + 2000, + bar_text["margin"], + horizontalalignment="center", + ) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() + def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -150,40 +199,52 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k,v in y.items()]) + y_init = np.sum([v[0] for k, v in y.items()]) - for k,v in y.items(): - y1 = [yi+vi for yi, vi in zip(y0,v)] + for k, v in y.items(): + y1 = [yi + vi for yi, vi in zip(y0, v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, 'w') + ax.plot(x, y1 / y_init, "w") y0 = y1 # Define margin - ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') + ax.fill_between( + x, + y1 / y_init, + np.ones(len(x)), + color=color["Cost margin"], + label="Margin", + ) - final_margin = round( 100* (1 - y1[-1] / y_init), 1) + final_margin = round(100 * (1 - y1[-1] / y_init), 1) - y_margin = ((1 + y1[-1] / y_init) /2) + y_margin = (1 + y1[-1] / y_init) / 2 - margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' + margin_text = ( + " " + + str(final_margin) + + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" + ) right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], 'k') - ax.text(right_bound, y_margin, margin_text, verticalalignment='center') - ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], "k") + ax.text(right_bound, y_margin, margin_text, verticalalignment="center") + ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') - ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') + ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") + ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") - ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') + ax.set_ylabel( + "CapEx breakdown relative to \ncomponents imported from Europe, %" + ) if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index 2b1bdafe..eed5b2c9 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,12 +12,10 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')" + "optional_input": "unit, (optional, default: 'default')", } - output_config = { - "example_output": "unit" - } + output_config = {"example_output": "unit"} def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -45,9 +43,7 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return { - "example_detailed_output": self.result - } + return {"example_detailed_output": self.result} @property def total_cost(self): @@ -60,9 +56,7 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return { - "example_output": self.result - } + return {"example_output": self.result} # === Annotated Example === @@ -75,18 +69,21 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": {"depth": "m"}, # For common inputs that will be shared across many modules, - "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules - "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT - - - + "site": { + "depth": "m" + }, # For common inputs that will be shared across many modules, + "plant": { + "num_turbines": "int" + }, # it's best to look up how the variable is named in existing modules + "turbine": { + "turbine_rating": "MW" + }, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -97,8 +94,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -114,13 +111,18 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above - - - self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library( + config, **kwargs + ) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config( + config + ) # if it hasn't already been and validate the config against '.expected_config' from above + + self._design = self.config.get( + "spar_design", {} + ) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -152,7 +154,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) return mass @@ -174,8 +176,10 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get( + "stiffened_column_CR", 3120 + ) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -194,7 +198,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 return mass @@ -219,7 +223,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating ** 0.5) * log(rating) + + 0.196 * (rating**0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -267,7 +271,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index e15c8156..4cc5fa25 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,7 +11,6 @@ def test_wisdem_monopile_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -23,7 +22,6 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -35,7 +33,6 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): - prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index a480e04e..5579f62c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,6 @@ import pytest from marmot import Environment - from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -24,27 +23,23 @@ def pytest_configure(): @pytest.fixture() def env(): - return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): - specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): - specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): - specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -53,7 +48,6 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): - specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -62,19 +56,16 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): - specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): - return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): - yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index 0ce94758..b5f5208b 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,7 +8,6 @@ import pandas as pd import pytest from marmot import le - from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 7320a9f6..9cac3f50 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -58,7 +57,6 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): - project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 915af401..6415118d 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,7 +8,6 @@ import pytest from marmot import Environment - from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -19,7 +18,6 @@ def __init__(self): def test_port_creation(): - env = Environment() port = Port(env) item = SampleItem() @@ -32,7 +30,6 @@ def test_port_creation(): def test_get_item(): - env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index cd1ad5cd..39c42a82 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -209,7 +208,6 @@ def test_correct_turbines(): def test_floating_calculations(): - base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index e1cf3024..ce7a1cd5 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,7 +11,6 @@ import numpy as np import pytest - from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -111,7 +110,6 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): - c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index 9db78fed..dbe18324 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,7 +8,6 @@ from copy import deepcopy import pytest - from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -104,7 +103,6 @@ def test_design_result(): def test_floating_length_calculations(): - base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 0762b46b..2f69ed18 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,7 +10,6 @@ from itertools import product import pytest - from ORBIT.phases.design import MonopileDesign base = { @@ -37,7 +36,6 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): - config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -61,7 +59,6 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): - test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -80,7 +77,6 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -93,7 +89,6 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): - test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -107,7 +102,6 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): - config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index 88a7a747..c59ef535 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,7 +9,6 @@ from copy import deepcopy import pytest - from ORBIT.phases.design import MooringSystemDesign base = { @@ -21,7 +20,6 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): - config = deepcopy(base) config["site"]["depth"] = depth @@ -34,7 +32,6 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): - config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -46,7 +43,6 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): - m = MooringSystemDesign(base) m.run() @@ -75,7 +71,6 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): - config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index b2dd6316..f17b3bd7 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -24,7 +23,6 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -51,7 +49,6 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): - test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -72,7 +69,6 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index 301e5894..d4168fd1 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,7 +10,6 @@ import numpy as np import pytest - from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 7c710fb9..30a134f3 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index 393cf7c1..dbc937c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,7 +8,6 @@ from itertools import product import pytest - from ORBIT.phases.design import SparDesign base = { @@ -23,7 +22,6 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): - config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -41,7 +39,6 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): - test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -54,7 +51,6 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): - config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index 5a01c14b..f9b1c9a9 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ArrayCableInstallation(config) assert sim.env @@ -37,7 +35,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -53,7 +50,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -72,7 +68,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,7 +84,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -114,7 +108,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): - sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -131,7 +124,6 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -163,7 +155,6 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): - base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -183,7 +174,6 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index 3ab42d15..f3d03350 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -28,7 +27,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -59,7 +57,6 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): - env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index 34669075..e837176c 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,7 +27,6 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): - sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -42,7 +40,6 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): - sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -58,7 +55,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): - sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -77,7 +73,6 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): - sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -94,7 +89,6 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): - sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -119,7 +113,6 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -150,7 +143,6 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: @@ -182,7 +174,6 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): - new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -214,7 +205,6 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index 6811e631..c601a5c6 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = JacketInstallation(config, weather=weather) sim.run() @@ -97,7 +93,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): - base = JacketInstallation(config) base.run() @@ -116,7 +111,6 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): - base = JacketInstallation(config) base.run() @@ -134,7 +128,6 @@ def test_foundation_type(config): def test_kwargs_piles(): - sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -154,7 +147,6 @@ def test_kwargs_piles(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -176,7 +168,6 @@ def test_kwargs_piles(): def test_kwargs_suction(): - config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -197,7 +188,6 @@ def test_kwargs_suction(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 57538063..1759bc3e 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -29,7 +28,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -50,7 +48,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -74,7 +71,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = MonopileInstallation(config, weather=weather) sim.run() @@ -92,7 +88,6 @@ def test_for_complete_logging(weather, config): def test_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -113,7 +108,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -145,7 +139,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -168,7 +161,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -203,7 +195,6 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): - sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index bff023f5..2fa11d9e 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -35,7 +34,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -55,7 +53,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 116f7558..3583bbda 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -61,7 +60,6 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): - new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -74,7 +72,6 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -103,7 +100,6 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): - base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -117,7 +113,6 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index be32be3d..30ed4475 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): - sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -45,7 +43,6 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): - sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -58,7 +55,6 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): - sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -82,7 +78,6 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -104,7 +99,6 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): - sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -118,7 +112,6 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): - sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -139,7 +132,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": @@ -171,7 +163,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -195,7 +186,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 67a28c40..758df489 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -25,7 +24,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -44,7 +42,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index 00fa2b4e..b9a08bac 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -28,7 +27,6 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): - _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -54,7 +52,6 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): - _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -92,7 +89,6 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): - num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index dafad84b..25d7db92 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index e1fc0af7..72619642 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,7 +8,6 @@ import pandas as pd import pytest - from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -18,7 +17,6 @@ def test_simulation_setup(): - sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -41,7 +39,6 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): - sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index 85e372c7..ae1c9313 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,7 +12,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -51,7 +50,6 @@ def test_full_run_logging(weather): def test_kwargs(): - sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -61,7 +59,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -83,7 +80,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -96,7 +92,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index 6b600eb2..cba9802c 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,7 +9,6 @@ import pandas as pd import pytest from marmot import Environment - from ORBIT.phases.install import InstallPhase @@ -45,7 +44,6 @@ def setup_simulation(self): def test_abstract_methods(): - with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -53,7 +51,6 @@ def test_abstract_methods(): def test_run(): - sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index aac2de9f..0592999a 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,7 +10,6 @@ import pandas as pd import pytest - from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -33,7 +32,6 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): - sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -56,7 +54,6 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): - sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -80,7 +77,6 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): - sim = TurbineInstallation(config) assert sim.wtiv @@ -97,7 +93,6 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): - sim = TurbineInstallation(config, weather=weather) sim.run() @@ -120,7 +115,6 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): - sim = TurbineInstallation(config) sim.run() @@ -131,7 +125,6 @@ def test_for_complete_installation(config): def test_kwargs(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -153,7 +146,6 @@ def test_kwargs(): failed = [] for kw in keywords: - default = pt[kw] kwargs = {kw: default + 2} @@ -175,7 +167,6 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): - base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -200,7 +191,6 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: - default = pt[kw] processes = {kw: default + 2} @@ -225,7 +215,6 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): - sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -245,7 +234,6 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): - vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 055da73d..2042f639 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,7 +9,6 @@ import pytest - from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -33,7 +32,6 @@ ], ) def test_task(env, wtiv, task, log, args): - env.register(wtiv) wtiv.initialize(mobilize=False) @@ -56,7 +54,6 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): - env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 209983ac..01e37b7b 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,14 +18,12 @@ def test_good_config(): - config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): - config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -33,7 +31,6 @@ def test_missing_key(): def test_optional(): - config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -41,7 +38,6 @@ def test_optional(): def test_variable_key(): - config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -50,7 +46,6 @@ def test_variable_key(): def test_optional_dict(): - config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index f635f271..ffd84920 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,7 +7,6 @@ import os import pytest - from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -15,7 +14,6 @@ def test_save_and_load_equality(tmp_yaml_del): - save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -23,7 +21,6 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): - config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 059202fb..656db0d8 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,9 +6,8 @@ from copy import deepcopy -from numpy.testing import assert_almost_equal - from ORBIT import ProjectManager +from numpy.testing import assert_almost_equal from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -16,7 +15,6 @@ def test_fixed_phase_cost_passing(): - project = ProjectManager(fixed) project.run() @@ -47,7 +45,6 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): - project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 4d73da75..5d33cfca 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,9 +7,8 @@ import pandas as pd import pytest -from benedict import benedict - from ORBIT import ProjectManager, ParametricManager +from benedict import benedict from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -24,7 +23,6 @@ def test_for_equal_results(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -37,7 +35,6 @@ def test_for_equal_results(): def test_weather(): - without = ParametricManager(complete_project, params, funcs) without.run() @@ -50,7 +47,6 @@ def test_weather(): def test_individual_phase(): - config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -67,7 +63,6 @@ def test_individual_phase(): def test_bad_result_attribute(): - funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -79,7 +74,6 @@ def test_bad_result_attribute(): def test_bad_result_structure(): - funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -91,7 +85,6 @@ def test_bad_result_structure(): def test_product_option(): - params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 7e62a225..9cbf9ad3 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,10 +8,9 @@ import pandas as pd import pytest - from ORBIT import ProjectManager -from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather +from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -26,10 +25,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") + ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): - project = ProjectManager(config, weather=weather) project.run() @@ -47,11 +46,9 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: - assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: - assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -130,7 +127,6 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: - i, expected = test response = TestProjectManager.find_key_match(i) @@ -143,13 +139,11 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: - assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): - config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -169,7 +163,6 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): - config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -233,7 +226,6 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): - config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -283,7 +275,6 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): - # Not a subclass class CustomInstallPhase: pass @@ -305,7 +296,6 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) - # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -318,11 +308,13 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase + assert ( + ProjectManager.find_key_match("CustomInstallPhase") + == CustomInstallPhase + ) def test_custom_design_phases(): - # Not a subclass class CustomDesignPhase: pass @@ -344,7 +336,6 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) - # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -357,11 +348,13 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + assert ( + ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase + ) + ### Design Phase Interactions def test_design_phases(): - config_with_design = deepcopy(config) # Add MonopileDesign @@ -386,7 +379,6 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): - # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -467,7 +459,6 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): - incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -477,7 +468,6 @@ def test_incomplete_config(): def test_wrong_phases(): - wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -487,7 +477,6 @@ def test_wrong_phases(): def test_bad_dates(): - bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -500,7 +489,6 @@ def test_bad_dates(): def test_no_defined_start(): - missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -513,7 +501,6 @@ def test_no_defined_start(): def test_circular_dependencies(): - circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -532,7 +519,6 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): - wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -552,7 +538,6 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): - data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -592,7 +577,6 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): - project = ProjectManager(config) project.run() @@ -607,7 +591,6 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): - project = ProjectManager(complete_project) project.run() @@ -633,7 +616,6 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -649,7 +631,6 @@ def test_monthly_expenses(): def test_monthly_revenue(): - project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -666,7 +647,6 @@ def test_monthly_revenue(): def test_cash_flow(): - project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -684,7 +664,6 @@ def test_cash_flow(): def test_npv(): - project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -721,7 +700,6 @@ def test_npv(): def test_soft_costs(): - project = ProjectManager(complete_project) baseline = project.soft_capex @@ -757,7 +735,6 @@ def test_soft_costs(): def test_project_costs(): - project = ProjectManager(complete_project) baseline = project.project_capex @@ -783,7 +760,6 @@ def test_project_costs(): def test_capex_categories(): - project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 64fea1c8..96361d2f 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,4 +1,3 @@ - # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -277,16 +276,18 @@ """ from __future__ import print_function + +import os +import re +import sys +import json +import errno +import subprocess + try: import configparser except ImportError: import ConfigParser as configparser -import errno -import json -import os -import re -import subprocess -import sys class VersioneerConfig: @@ -308,11 +309,13 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") + err = ( + "Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND')." + ) raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -325,8 +328,10 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) + print( + "Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py) + ) except NameError: pass return root @@ -348,6 +353,7 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None + cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -372,17 +378,20 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" + def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f + return decorate -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): +def run_command( + commands, args, cwd=None, verbose=False, hide_stderr=False, env=None +): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -390,10 +399,13 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) + p = subprocess.Popen( + [c] + args, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr else None), + ) break except EnvironmentError: e = sys.exc_info()[1] @@ -418,7 +430,9 @@ def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, return stdout, p.returncode -LONG_VERSION_PY['git'] = ''' +LONG_VERSION_PY[ + "git" +] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -993,7 +1007,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1002,7 +1016,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) + tags = set([r for r in refs if re.search(r"\d", r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1010,19 +1024,26 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] + r = ref[len(tag_prefix) :] if verbose: print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} + return { + "version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": None, + "date": date, + } # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} + return { + "version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, + "error": "no suitable tags", + "date": None, + } @register_vcs_handler("git", "pieces_from_vcs") @@ -1037,8 +1058,9 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) + out, rc = run_command( + GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True + ) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1046,10 +1068,19 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%s*" % tag_prefix], - cwd=root) + describe_out, rc = run_command( + GITS, + [ + "describe", + "--tags", + "--dirty", + "--always", + "--long", + "--match", + "%s*" % tag_prefix, + ], + cwd=root, + ) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1072,17 +1103,18 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] + git_describe = git_describe[: git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) + mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) + pieces["error"] = ( + "unable to parse git-describe output: '%s'" % describe_out + ) return pieces # tag @@ -1091,10 +1123,12 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) + pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( + full_tag, + tag_prefix, + ) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] + pieces["closest-tag"] = full_tag[len(tag_prefix) :] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1105,13 +1139,15 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) + count_out, rc = run_command( + GITS, ["rev-list", "HEAD", "--count"], cwd=root + ) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ + 0 + ].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1167,16 +1203,22 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} + return { + "version": dirname[len(parentdir_prefix) :], + "full-revisionid": None, + "dirty": False, + "error": None, + "date": None, + } else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) + print( + "Tried directories %s but none started with prefix %s" + % (str(rootdirs), parentdir_prefix) + ) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1205,11 +1247,17 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) + mo = re.search( + r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, + re.M | re.S, + ) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1218,8 +1266,9 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) + contents = json.dumps( + versions, sort_keys=True, indent=1, separators=(",", ": ") + ) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1251,8 +1300,7 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1366,11 +1414,13 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} + return { + "version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None, + } if not style or style == "default": style = "pep440" # the default @@ -1390,9 +1440,13 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} + return { + "version": rendered, + "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], + "error": None, + "date": pieces.get("date"), + } class VersioneerBadRootError(Exception): @@ -1415,8 +1469,9 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" + assert ( + cfg.versionfile_source is not None + ), "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1470,9 +1525,13 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} + return { + "version": "0+unknown", + "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", + "date": None, + } def get_version(): @@ -1521,6 +1580,7 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) + cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1553,14 +1613,17 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) + target_versionfile = os.path.join( + self.build_lib, cfg.versionfile_build + ) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) + cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe + # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1581,17 +1644,21 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if 'py2exe' in sys.modules: # py2exe enabled? + if "py2exe" in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1610,13 +1677,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1643,8 +1714,10 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + write_to_version_file( + target_versionfile, self._versioneer_generated_versions + ) + cmds["sdist"] = cmd_sdist return cmds @@ -1699,11 +1772,15 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: + except ( + EnvironmentError, + configparser.NoSectionError, + configparser.NoOptionError, + ) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) + print( + "Adding sample versioneer config to setup.cfg", file=sys.stderr + ) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1712,15 +1789,18 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") + f.write( + LONG + % { + "DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + } + ) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1762,8 +1842,10 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) + print( + " appending versionfile_source ('%s') to MANIFEST.in" + % cfg.versionfile_source + ) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From b7de3734f9208e67e8a14186516e4ea968901534 Mon Sep 17 00:00:00 2001 From: Jake Nunemaker Date: Wed, 1 Mar 2023 13:52:20 -0700 Subject: [PATCH 13/19] Updated pre-commit.ci. --- .pre-commit-config.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 041152aa..84ca9757 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,3 +1,6 @@ +ci: + skip: [isort, black, pylint] + repos: - repo: https://github.com/timothycrosley/isort rev: 4.3.21 From 9f84546c71dc3aa82b204a6405d1e6d14004c0e1 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 1 Mar 2023 13:54:43 -0700 Subject: [PATCH 14/19] Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" This reverts commit b1e53ed8676aaa00476d477064aca7922c3aa7b9. --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++------ ORBIT/api/wisdem.py | 1 + ORBIT/config.py | 1 + ORBIT/core/cargo.py | 1 + ORBIT/core/components.py | 1 + ORBIT/core/defaults/__init__.py | 1 + ORBIT/core/environment.py | 2 + ORBIT/core/exceptions.py | 1 + ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 + ORBIT/core/port.py | 1 + ORBIT/core/supply_chain.py | 1 + ORBIT/core/vessel.py | 2 + ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 + ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 8 +- ORBIT/phases/design/export_system_design.py | 2 + ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 + ORBIT/phases/install/cable_install/common.py | 1 + ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 + ORBIT/phases/install/jacket_install/common.py | 1 + .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 + .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 + ORBIT/phases/install/oss_install/common.py | 2 + ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 + .../quayside_assembly_tow/gravity_base.py | 3 + .../install/quayside_assembly_tow/moored.py | 3 + .../scour_protection_install/standard.py | 1 + .../phases/install/turbine_install/common.py | 1 + .../install/turbine_install/standard.py | 4 + ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 ++++------- templates/design_module.py | 74 ++--- tests/api/test_wisdem_api.py | 3 + tests/conftest.py | 9 + tests/core/test_environment.py | 1 + tests/core/test_library.py | 2 + tests/core/test_port.py | 3 + .../phases/design/test_array_system_design.py | 2 + tests/phases/design/test_cable.py | 2 + .../design/test_export_system_design.py | 2 + tests/phases/design/test_monopile_design.py | 6 + .../design/test_mooring_system_design.py | 5 + tests/phases/design/test_oss_design.py | 4 + .../design/test_scour_protection_design.py | 1 + .../design/test_semisubmersible_design.py | 4 + tests/phases/design/test_spar_design.py | 4 + .../cable_install/test_array_install.py | 10 + .../install/cable_install/test_cable_tasks.py | 3 + .../cable_install/test_export_install.py | 10 + .../jacket_install/test_jacket_install.py | 10 + .../monopile_install/test_monopile_install.py | 9 + .../monopile_install/test_monopile_tasks.py | 3 + .../mooring_install/test_mooring_install.py | 5 + .../install/oss_install/test_oss_install.py | 10 + .../install/oss_install/test_oss_tasks.py | 3 + .../quayside_assembly_tow/test_common.py | 4 + .../test_gravity_based.py | 3 + .../quayside_assembly_tow/test_moored.py | 3 + .../test_scour_protection.py | 5 + tests/phases/install/test_install_phase.py | 3 + .../turbine_install/test_turbine_install.py | 12 + .../turbine_install/test_turbine_tasks.py | 3 + tests/phases/test_base.py | 5 + tests/test_config_management.py | 3 + .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 ++- versioneer.py | 298 +++++++----------- 85 files changed, 716 insertions(+), 626 deletions(-) diff --git a/LICENSE b/LICENSE index 1c0c15ea..dbb692d8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index f03f6681..fa1e63bc 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,3 +1,4 @@ + # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -9,11 +10,11 @@ """Git implementation of _version.py.""" +import errno import os import re -import sys -import errno import subprocess +import sys def get_keywords(): @@ -57,20 +58,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -78,13 +76,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -121,22 +116,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -192,7 +181,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -201,7 +190,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -209,26 +198,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -243,9 +225,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -253,19 +234,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -288,18 +260,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -308,12 +279,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -324,15 +293,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -363,7 +330,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -477,13 +445,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -503,13 +469,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} def get_versions(): @@ -523,9 +485,8 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords( - get_keywords(), cfg.tag_prefix, verbose - ) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) except NotThisMethod: pass @@ -534,16 +495,13 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split("/"): + for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -557,10 +515,6 @@ def get_versions(): except NotThisMethod: pass - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 63fd1460..8320e99c 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,6 +7,7 @@ import openmdao.api as om + from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 5a416b43..4a50732d 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,6 +8,7 @@ import yaml from yaml import Dumper + from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index 0f618b4e..d02ab03f 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,6 +6,7 @@ class Cargo(Object): + def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index dec26889..e4e3792c 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,6 +6,7 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 1cc75bae..7df591ec 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,6 +8,7 @@ import os import yaml + from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index bade7d84..4654ec13 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,6 +88,7 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): + if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -138,6 +139,7 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): + if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index ec9fa5d6..8d7d0ca4 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,6 +31,7 @@ def __init__(self, vessel, component): ) def __str__(self): + return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index c8217b15..6f771cc0 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper + from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") - # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index daa4a707..b27a3e78 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -148,6 +149,7 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: + if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -260,13 +262,16 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: + if proposed_deck_space > vessel.storage.max_deck_space: + msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: + msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -327,6 +332,7 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: + vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index c24ccfa6..dbfc152a 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,6 +7,7 @@ import simpy + from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 6f271c9b..0f2f3e1a 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,6 +41,7 @@ def __init__( @process def start(self): + n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index c952e905..88c823a4 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,6 +15,7 @@ WindowNotFound, AgentNotRegistered, ) + from ORBIT.core.components import ( Crane, JackingSys, @@ -85,6 +86,7 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): + duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index ccb0a47d..6aeb5ba1 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,9 +14,10 @@ from itertools import product import numpy as np -import ORBIT import pandas as pd from benedict import benedict + +import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -166,12 +167,14 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): + try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): + idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -202,9 +205,7 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -228,9 +229,7 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -454,6 +453,7 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): + if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,6 +500,7 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): + ret = {} for k, t in self.phase_times.items(): try: @@ -692,6 +693,7 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): + _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -725,6 +727,7 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: + phases = {**phases, **skipped} if not phases: break @@ -823,6 +826,7 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): + if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1100,6 +1104,7 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): + unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1135,6 +1140,7 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): + start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 634b842c..6895400c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,10 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager + class ParametricManager: """Class for configuring parametric ORBIT runs.""" @@ -201,6 +202,7 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): + split = v.split("[") attr = split[0] @@ -296,6 +298,7 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): + if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 1b39d91a..2e9b539d 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,6 +10,7 @@ from copy import deepcopy from benedict import benedict + from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -69,6 +70,7 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): + if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 1b93d209..27343a58 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,6 +11,7 @@ import numpy as np from scipy.optimize import fsolve + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -332,7 +333,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 28b780d9..6fbf911d 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,6 +12,7 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt + from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.core.exceptions import LibraryItemNotFoundError from ORBIT.phases.design._cables import Plant, CableSystem @@ -383,7 +384,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -578,6 +579,7 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): + ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -742,7 +744,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError @@ -812,6 +814,7 @@ def create_project_csv(self, save_name, folder="cables"): export_library_specs(folder, save_name, rows, file_ext="csv") def _format_windfarm_data(self): + # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1059,6 +1062,7 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): + self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index bf7af015..6c6ae0a0 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,6 +6,7 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np + from ORBIT.phases.design._cables import CableSystem @@ -212,6 +213,7 @@ def design_result(self): } for name, cable in self.cables.items(): + output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index 082b3a9c..ab1e5349 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,6 +9,7 @@ from math import pi, log from scipy.optimize import fsolve + from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -229,7 +230,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp**2, + "deck_space": D_tp ** 2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -354,7 +355,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -559,7 +560,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 0dcf67d8..383a4924 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index ea72c993..1a2fe071 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,6 +7,7 @@ import numpy as np + from ORBIT.phases.design import DesignPhase @@ -283,7 +284,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass**0.5574 + substructure_pile_mass = 8 * substructure_mass ** 0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index d36b91eb..efa66b4f 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,6 +8,7 @@ from math import ceil import numpy as np + from ORBIT.phases.design import DesignPhase @@ -114,7 +115,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 7bb34217..58404a29 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating**2 + 6.54 * rating + 128.34 + mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index c8b0862e..224c4a5e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,6 +7,7 @@ from numpy import exp, log + from ORBIT.phases.design import DesignPhase @@ -71,7 +72,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -112,7 +113,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -137,7 +138,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index 21120126..d4d8a181 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,6 +10,7 @@ import numpy as np from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -236,6 +237,7 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: + try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -267,6 +269,7 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: + try: length, num_sections, *extra = sections.pop(0) if extra: @@ -288,10 +291,12 @@ def install_array_cables( break for _ in range(num_sections): + try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: + yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index fa0833f2..f2481138 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 55bf7d32..486bc9e7 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,6 +10,7 @@ from math import ceil from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -182,7 +183,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity**0.3549 + 350000 + onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index c4d159d6..97b93c3b 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,6 +12,7 @@ import numpy as np import simpy import pandas as pd + from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 5cd9feb2..4312bfcf 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,6 +5,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 10391d6e..2f8f0c55 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,6 +7,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -110,7 +111,9 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ """ + """ + + """ jacket = Jacket(**self.config["jacket"]) @@ -129,6 +132,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): + items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -369,6 +373,7 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -433,7 +438,9 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index ee1fcb74..04af017a 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,6 +7,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -339,6 +340,7 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 02c7c259..5a204709 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,6 +9,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -105,7 +106,9 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ """ + """ + + """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -116,6 +119,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): + delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -342,6 +346,7 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -403,7 +408,9 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index c4175f28..3b3573b9 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -160,7 +161,9 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: + system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f1c5527b..f90128ac 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -138,6 +139,7 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index a293363d..6580e19a 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,10 +6,11 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, le, process +from marmot import Agent, process, le +from marmot._exceptions import AgentNotRegistered + from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite -from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -143,6 +144,7 @@ def initialize_installation_vessel(self): @property def detailed_output(self): + return {} @@ -173,6 +175,7 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): + start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -193,7 +196,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range(3): + for _ in range (3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 15bcbd79..04038af9 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,6 +8,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -229,7 +230,9 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index a02a3547..4cbd97f6 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,6 +293,7 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -355,6 +357,7 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index 8376b274..c38908b2 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -291,6 +292,7 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -364,6 +366,7 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index db1c8ce6..9dd3ee9a 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,6 +10,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index f65aa7a3..057ff1bd 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index 58e273ab..d23515a1 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,6 +12,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -320,6 +321,7 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -405,7 +407,9 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index 8290eae7..b17e2ae8 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,47 +5,71 @@ from copy import deepcopy - -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager -DEFAULT_MULTIPLIERS = { - "blades": {"domestic": 0.026, "imported": 0.30}, - "nacelle": {"domestic": 0.025, "imported": 0.10}, - "tower": { - "domestic": 0.04, - "imported": 0.20, - "tariffs": 0.25, - }, - "monopile": { - "domestic": 0.085, - "imported": 0.28, - "tariffs": 0.25, - }, - "transition_piece": { - "domestic": 0.169, - "imported": 0.17, - "tariffs": 0.25, - }, - "array_cable": {"domestic": 0.19, "imported": 0.0}, - "export_cable": {"domestic": 0.231, "imported": 0.0}, - "oss_topside": {"domestic": 0.0, "imported": 0.0}, - "oss_substructure": {"domestic": 0.0, "imported": 0.0}, -} -TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} +DEFAULT_MULTIPLIERS = { + "blades": { + "domestic": .026, + "imported": .30 + }, + "nacelle": { + "domestic": .025, + "imported": .10 + }, + "tower": { + "domestic": .04, + "imported": .20, + "tariffs": .25, + }, + "monopile": { + "domestic": .085, + "imported": .28, + "tariffs": .25, + }, + "transition_piece": { + "domestic": .169, + "imported": .17, + "tariffs": .25, + }, + "array_cable": { + "domestic": .19, + "imported": 0. + }, + "export_cable": { + "domestic": .231, + "imported": 0. + }, + "oss_topside": { + "domestic": 0., + "imported": 0. + }, + "oss_substructure": { + "domestic": 0., + "imported": 0. + }, + } + + +TURBINE_CAPEX_SPLIT = { + "blades": 0.135, + "nacelle": 0.274, + "tower": 0.162 +} LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5, + "oss_topside": 0.5 } class SupplyChainManager: + def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -87,17 +111,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config["plant"]) + plant = deepcopy(config['plant']) # Run ProjectManager without install phases to generate design results - install_phases = config["install_phases"] - config["install_phases"] = [] + install_phases = config['install_phases'] + config['install_phases'] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config["plant"] = plant + config['plant'] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -106,8 +130,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config["install_phases"] = install_phases - config["design_phases"] = [] + config['install_phases'] = install_phases + config['design_phases'] = [] return config @@ -130,51 +154,45 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config["blades"] - nacelle_scenario = self.sc_config["nacelle"] - tower_scenario = self.sc_config["blades"] + blade_scenario = self.sc_config['blades'] + nacelle_scenario = self.sc_config['nacelle'] + tower_scenario = self.sc_config['blades'] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print( - f"Warning: scenario '{blade_scenario}' not found for category 'blades'." - ) - blade_mult = 0.0 + print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") + blade_mult = 0. nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print( - f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." - ) - nacelle_mult = 0.0 + print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") + nacelle_mult = 0. - raw_cost = config.get("project_parameters.turbine_capex", 1300) - blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult - nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult + raw_cost = config.get('project_parameters.turbine_capex', 1300) + blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult + nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = ( - raw_cost - * self.turbine_split["tower"] - * (1 - self.labor_split["tower"]) - * self.multipliers["tower"]["tariffs"] - ) + tower_tariffs = raw_cost * self.turbine_split['tower'] *\ + (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] else: - tower_tariffs = 0.0 + tower_tariffs = 0. tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print( - f"Warning: scenario '{tower_scenario}' not found for category 'tower'." - ) - tower_mult = 0.0 + print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") + tower_mult = 0. - tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult + tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult - config["project_parameters.turbine_capex"] = sum( - [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] - ) + config['project_parameters.turbine_capex'] = sum([ + raw_cost, + blade_adder, + nacelle_adder, + tower_adder, + tower_tariffs + ]) return config @@ -188,29 +206,28 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config["monopile.unit_cost"] - scenario = self.sc_config["monopile"] + raw_cost = config['monopile.unit_cost'] + scenario = self.sc_config['monopile'] if scenario == "domestic, imported steel": - adder = self.multipliers["monopile"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["monopile"]) - * self.multipliers["monopile"]["tariffs"] - ) + adder = self.multipliers['monopile']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ + self.multipliers["monopile"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'monopile'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") + mult = 0. adder = raw_cost * mult - config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['monopile.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -225,29 +242,28 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config["transition_piece.unit_cost"] - scenario = self.sc_config["transition_piece"] + raw_cost = config['transition_piece.unit_cost'] + scenario = self.sc_config['transition_piece'] if scenario == "domestic, imported steel": - adder = self.multipliers["transition_piece"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["transition_piece"]) - * self.multipliers["transition_piece"]["tariffs"] - ) + adder = self.multipliers['transition_piece']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ + self.multipliers["transition_piece"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'transition_piece'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") + mult = 0. adder = raw_cost * mult - config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['transition_piece.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -262,31 +278,28 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config["offshore_substation_topside.unit_cost"] - scenario = self.sc_config["oss_topside"] + raw_cost = config['offshore_substation_topside.unit_cost'] + scenario = self.sc_config['oss_topside'] if scenario == "domestic, imported steel": - adder = self.multipliers["oss_topside"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["oss_topside"]) - * self.multipliers["oss_topside"]["tariffs"] - ) + adder = self.multipliers['oss_topside']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ + self.multipliers["oss_topside"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'oss_topside'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") + mult = 0. adder = raw_cost * mult - config["offshore_substation_topside.unit_cost"] = sum( - [raw_cost, adder, tariffs] - ) + config['offshore_substation_topside.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -300,15 +313,13 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["array_cable"] + scenario = self.sc_config['array_cable'] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'array_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") + mult = 0. - project.system_costs["ArrayCableInstallation"] *= 1 + mult + project.system_costs['ArrayCableInstallation'] *= (1 + mult) return project @@ -321,14 +332,12 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["export_cable"] + scenario = self.sc_config['export_cable'] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'export_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") + mult = 0. - project.system_costs["ExportCableInstallation"] *= 1 + mult + project.system_costs['ExportCableInstallation'] *= (1 + mult) return project diff --git a/docs/Makefile b/docs/Makefile index 51285967..298ea9e2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 555a6637..38ceb207 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -import ORBIT - sys.path.insert(0, os.path.abspath("..")) +import ORBIT + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 0a3683f9..50478a79 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW +turbine_rating: 15 # MW \ No newline at end of file diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 00a13ba3..75b6fd5c 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,40 +1,31 @@ -import os +import pandas as pd import math - import numpy as np -import pandas as pd import matplotlib as mpl -import matplotlib.text as txt import matplotlib.pyplot as plt +import matplotlib.text as txt +import os - -def mysave(fig, froot, mode="png"): - assert mode in ["png", "eps", "pdf", "all"] +def mysave(fig, froot, mode='png'): + assert mode in ['png', 'eps', 'pdf', 'all'] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: - legs.append(a.get_legend()) + if not addLeg is None: legs.append(a.get_legend()) ext = [] - if mode == "png" or mode == "all": - ext.append("png") - if mode == "eps": # or mode == 'all': - ext.append("eps") - if mode == "pdf" or mode == "all": - ext.append("pdf") + if mode == 'png' or mode == 'all': + ext.append('png') + if mode == 'eps': # or mode == 'all': + ext.append('eps') + if mode == 'pdf' or mode == 'all': + ext.append('pdf') for sfx in ext: - fig.savefig( - fileName + "." + sfx, - format=sfx, - pad_inches=padding, - bbox_inches="tight", - dpi=dpiVal, - bbox_extra_artists=legs, - ) + fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', + dpi=dpiVal, bbox_extra_artists=legs) titleSize = 24 # 40 #38 @@ -47,48 +38,32 @@ def mysave(fig, froot, mode="png"): linewidth = 3 -def myformat( - ax, - linewidth=linewidth, - xticklabel=tickLabelSize, - yticklabel=tickLabelSize, - mode="save", -): - assert type(mode) == type("") - assert mode.lower() in ["save", "show"], "Unknown mode" - - def myformat( - myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel - ): - if mode.lower() == "show": +def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): + assert type(mode) == type('') + assert mode.lower() in ['save', 'show'], 'Unknown mode' + + def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): + if mode.lower() == 'show': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title( - myax.get_title(), size=titleSize + deltaShow, weight="bold" - ) - myax.set_xlabel( - myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" - ) - myax.set_ylabel( - myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" - ) + myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -100,29 +75,27 @@ def myformat( for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == "save": + elif mode.lower() == 'save': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize) + for t in leg.get_texts(): t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight="bold") - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") + myax.set_title(myax.get_title(), size=titleSize, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -135,62 +108,40 @@ def myformat( i.set_linewidth(3) if type(ax) == type([]): - for i in ax: - myformat(i) + for i in ax: myformat(i) else: myformat(ax) - def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax - def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """Waterfall plot comparing European andUS manufactining costs""" + """ Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") + h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) - ) - ax.set_ylabel("Capital Expenditures, $/kW") - ax.set_title( - "Comparison of different cost premiums between \nimported and domestically manufactured components" - ) - - h[3].set_linestyle("--") + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) + ax.set_ylabel('Capital Expenditures, $/kW') + ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') + + h[3].set_linestyle('--') h[3].set_linewidth(1.75) - h[3].set_edgecolor("k") - - ax.text( - x[1], - 2000, - bar_text["transit"], - horizontalalignment="center", - ) - ax.text( - x[2], - 2000, - bar_text["factory"], - horizontalalignment="center", - ) - ax.text( - x[3], - 2000, - bar_text["margin"], - horizontalalignment="center", - ) + h[3].set_edgecolor('k') + + ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) + ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) + ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() - def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -199,52 +150,40 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k, v in y.items()]) + y_init = np.sum([v[0] for k,v in y.items()]) - for k, v in y.items(): - y1 = [yi + vi for yi, vi in zip(y0, v)] + for k,v in y.items(): + y1 = [yi+vi for yi, vi in zip(y0,v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, "w") + ax.plot(x, y1 / y_init, 'w') y0 = y1 # Define margin - ax.fill_between( - x, - y1 / y_init, - np.ones(len(x)), - color=color["Cost margin"], - label="Margin", - ) + ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') - final_margin = round(100 * (1 - y1[-1] / y_init), 1) + final_margin = round( 100* (1 - y1[-1] / y_init), 1) - y_margin = (1 + y1[-1] / y_init) / 2 + y_margin = ((1 + y1[-1] / y_init) /2) - margin_text = ( - " " - + str(final_margin) - + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" - ) + margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], "k") - ax.text(right_bound, y_margin, margin_text, verticalalignment="center") - ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], 'k') + ax.text(right_bound, y_margin, margin_text, verticalalignment='center') + ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") - ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") + ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') + ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') - ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel( - "CapEx breakdown relative to \ncomponents imported from Europe, %" - ) + ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index eed5b2c9..2b1bdafe 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,10 +12,12 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')", + "optional_input": "unit, (optional, default: 'default')" } - output_config = {"example_output": "unit"} + output_config = { + "example_output": "unit" + } def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -43,7 +45,9 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return {"example_detailed_output": self.result} + return { + "example_detailed_output": self.result + } @property def total_cost(self): @@ -56,7 +60,9 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return {"example_output": self.result} + return { + "example_output": self.result + } # === Annotated Example === @@ -69,21 +75,18 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": { - "depth": "m" - }, # For common inputs that will be shared across many modules, - "plant": { - "num_turbines": "int" - }, # it's best to look up how the variable is named in existing modules - "turbine": { - "turbine_rating": "MW" - }, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + "site": {"depth": "m"}, # For common inputs that will be shared across many modules, + "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules + "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + + + # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -94,8 +97,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -111,18 +114,13 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library( - config, **kwargs - ) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config( - config - ) # if it hasn't already been and validate the config against '.expected_config' from above - - self._design = self.config.get( - "spar_design", {} - ) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above + + + self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -154,7 +152,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -176,10 +174,8 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get( - "stiffened_column_CR", 3120 - ) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -198,7 +194,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -223,7 +219,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -271,7 +267,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index 4cc5fa25..e15c8156 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,6 +11,7 @@ def test_wisdem_monopile_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -22,6 +23,7 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -33,6 +35,7 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index 5579f62c..a480e04e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ import pytest from marmot import Environment + from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -23,23 +24,27 @@ def pytest_configure(): @pytest.fixture() def env(): + return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): + specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): + specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): + specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -48,6 +53,7 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): + specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -56,16 +62,19 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): + specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): + return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): + yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index b5f5208b..0ce94758 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,6 +8,7 @@ import pandas as pd import pytest from marmot import le + from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 9cac3f50..7320a9f6 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -57,6 +58,7 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): + project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 6415118d..915af401 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,6 +8,7 @@ import pytest from marmot import Environment + from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -18,6 +19,7 @@ def __init__(self): def test_port_creation(): + env = Environment() port = Port(env) item = SampleItem() @@ -30,6 +32,7 @@ def test_port_creation(): def test_get_item(): + env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index 39c42a82..cd1ad5cd 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -208,6 +209,7 @@ def test_correct_turbines(): def test_floating_calculations(): + base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index ce7a1cd5..e1cf3024 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,6 +11,7 @@ import numpy as np import pytest + from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -110,6 +111,7 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): + c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index dbe18324..9db78fed 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,6 +8,7 @@ from copy import deepcopy import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -103,6 +104,7 @@ def test_design_result(): def test_floating_length_calculations(): + base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 2f69ed18..0762b46b 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,6 +10,7 @@ from itertools import product import pytest + from ORBIT.phases.design import MonopileDesign base = { @@ -36,6 +37,7 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): + config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -59,6 +61,7 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): + test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -77,6 +80,7 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -89,6 +93,7 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): + test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -102,6 +107,7 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index c59ef535..88a7a747 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT.phases.design import MooringSystemDesign base = { @@ -20,6 +21,7 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): + config = deepcopy(base) config["site"]["depth"] = depth @@ -32,6 +34,7 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): + config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -43,6 +46,7 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): + m = MooringSystemDesign(base) m.run() @@ -71,6 +75,7 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): + config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index f17b3bd7..b2dd6316 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -23,6 +24,7 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -49,6 +51,7 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): + test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -69,6 +72,7 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index d4168fd1..301e5894 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 30a134f3..7c710fb9 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index dbc937c1..393cf7c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SparDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index f9b1c9a9..5a01c14b 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ArrayCableInstallation(config) assert sim.env @@ -35,6 +37,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -50,6 +53,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -68,6 +72,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -84,6 +89,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -108,6 +114,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): + sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -124,6 +131,7 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -155,6 +163,7 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): + base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -174,6 +183,7 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index f3d03350..3ab42d15 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -27,6 +28,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -57,6 +59,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index e837176c..34669075 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -40,6 +42,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -55,6 +58,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -73,6 +77,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,6 +94,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -113,6 +119,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -143,6 +150,7 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -174,6 +182,7 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -205,6 +214,7 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index c601a5c6..6811e631 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = JacketInstallation(config, weather=weather) sim.run() @@ -93,6 +97,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): + base = JacketInstallation(config) base.run() @@ -111,6 +116,7 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): + base = JacketInstallation(config) base.run() @@ -128,6 +134,7 @@ def test_foundation_type(config): def test_kwargs_piles(): + sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -147,6 +154,7 @@ def test_kwargs_piles(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -168,6 +176,7 @@ def test_kwargs_piles(): def test_kwargs_suction(): + config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -188,6 +197,7 @@ def test_kwargs_suction(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 1759bc3e..57538063 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = MonopileInstallation(config, weather=weather) sim.run() @@ -88,6 +92,7 @@ def test_for_complete_logging(weather, config): def test_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -108,6 +113,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -139,6 +145,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -161,6 +168,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -195,6 +203,7 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index 2fa11d9e..bff023f5 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -34,6 +35,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -53,6 +55,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 3583bbda..116f7558 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -60,6 +61,7 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): + new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -72,6 +74,7 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -100,6 +103,7 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): + base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -113,6 +117,7 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index 30ed4475..be32be3d 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -43,6 +45,7 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): + sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -55,6 +58,7 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -78,6 +82,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -99,6 +104,7 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): + sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -112,6 +118,7 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): + sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -132,6 +139,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -163,6 +171,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -186,6 +195,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 758df489..67a28c40 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -24,6 +25,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -42,6 +44,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index b9a08bac..00fa2b4e 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -27,6 +28,7 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): + _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -52,6 +54,7 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): + _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -89,6 +92,7 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): + num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index 25d7db92..dafad84b 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index 72619642..e1fc0af7 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index ae1c9313..85e372c7 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -50,6 +51,7 @@ def test_full_run_logging(weather): def test_kwargs(): + sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -59,6 +61,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -80,6 +83,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -92,6 +96,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index cba9802c..6b600eb2 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,6 +9,7 @@ import pandas as pd import pytest from marmot import Environment + from ORBIT.phases.install import InstallPhase @@ -44,6 +45,7 @@ def setup_simulation(self): def test_abstract_methods(): + with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -51,6 +53,7 @@ def test_abstract_methods(): def test_run(): + sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index 0592999a..aac2de9f 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): + sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -54,6 +56,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): + sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -77,6 +80,7 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): + sim = TurbineInstallation(config) assert sim.wtiv @@ -93,6 +97,7 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = TurbineInstallation(config, weather=weather) sim.run() @@ -115,6 +120,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): + sim = TurbineInstallation(config) sim.run() @@ -125,6 +131,7 @@ def test_for_complete_installation(config): def test_kwargs(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -146,6 +153,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -167,6 +175,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -191,6 +200,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} @@ -215,6 +225,7 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -234,6 +245,7 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): + vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 2042f639..055da73d 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -32,6 +33,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -54,6 +56,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 01e37b7b..209983ac 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,12 +18,14 @@ def test_good_config(): + config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): + config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -31,6 +33,7 @@ def test_missing_key(): def test_optional(): + config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -38,6 +41,7 @@ def test_optional(): def test_variable_key(): + config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -46,6 +50,7 @@ def test_variable_key(): def test_optional_dict(): + config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index ffd84920..f635f271 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,6 +7,7 @@ import os import pytest + from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -14,6 +15,7 @@ def test_save_and_load_equality(tmp_yaml_del): + save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -21,6 +23,7 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): + config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 656db0d8..059202fb 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,8 +6,9 @@ from copy import deepcopy -from ORBIT import ProjectManager from numpy.testing import assert_almost_equal + +from ORBIT import ProjectManager from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -15,6 +16,7 @@ def test_fixed_phase_cost_passing(): + project = ProjectManager(fixed) project.run() @@ -45,6 +47,7 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): + project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 5d33cfca..4d73da75 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,8 +7,9 @@ import pandas as pd import pytest -from ORBIT import ProjectManager, ParametricManager from benedict import benedict + +from ORBIT import ProjectManager, ParametricManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -23,6 +24,7 @@ def test_for_equal_results(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -35,6 +37,7 @@ def test_for_equal_results(): def test_weather(): + without = ParametricManager(complete_project, params, funcs) without.run() @@ -47,6 +50,7 @@ def test_weather(): def test_individual_phase(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -63,6 +67,7 @@ def test_individual_phase(): def test_bad_result_attribute(): + funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -74,6 +79,7 @@ def test_bad_result_attribute(): def test_bad_result_structure(): + funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -85,6 +91,7 @@ def test_bad_result_structure(): def test_product_option(): + params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 9cbf9ad3..7e62a225 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,9 +8,10 @@ import pandas as pd import pytest + from ORBIT import ProjectManager +from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather -from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -25,10 +26,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") - ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): + project = ProjectManager(config, weather=weather) project.run() @@ -46,9 +47,11 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: + assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: + assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -127,6 +130,7 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: + i, expected = test response = TestProjectManager.find_key_match(i) @@ -139,11 +143,13 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: + assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): + config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -163,6 +169,7 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): + config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -226,6 +233,7 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): + config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -275,6 +283,7 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): + # Not a subclass class CustomInstallPhase: pass @@ -296,6 +305,7 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) + # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -308,13 +318,11 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ( - ProjectManager.find_key_match("CustomInstallPhase") - == CustomInstallPhase - ) + assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase def test_custom_design_phases(): + # Not a subclass class CustomDesignPhase: pass @@ -336,6 +344,7 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) + # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -348,13 +357,11 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ( - ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase - ) - + assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase ### Design Phase Interactions def test_design_phases(): + config_with_design = deepcopy(config) # Add MonopileDesign @@ -379,6 +386,7 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): + # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -459,6 +467,7 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): + incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -468,6 +477,7 @@ def test_incomplete_config(): def test_wrong_phases(): + wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -477,6 +487,7 @@ def test_wrong_phases(): def test_bad_dates(): + bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -489,6 +500,7 @@ def test_bad_dates(): def test_no_defined_start(): + missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -501,6 +513,7 @@ def test_no_defined_start(): def test_circular_dependencies(): + circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -519,6 +532,7 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): + wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -538,6 +552,7 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): + data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -577,6 +592,7 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): + project = ProjectManager(config) project.run() @@ -591,6 +607,7 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): + project = ProjectManager(complete_project) project.run() @@ -616,6 +633,7 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -631,6 +649,7 @@ def test_monthly_expenses(): def test_monthly_revenue(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -647,6 +666,7 @@ def test_monthly_revenue(): def test_cash_flow(): + project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -664,6 +684,7 @@ def test_cash_flow(): def test_npv(): + project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -700,6 +721,7 @@ def test_npv(): def test_soft_costs(): + project = ProjectManager(complete_project) baseline = project.soft_capex @@ -735,6 +757,7 @@ def test_soft_costs(): def test_project_costs(): + project = ProjectManager(complete_project) baseline = project.project_capex @@ -760,6 +783,7 @@ def test_project_costs(): def test_capex_categories(): + project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 96361d2f..64fea1c8 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,3 +1,4 @@ + # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -276,18 +277,16 @@ """ from __future__ import print_function - -import os -import re -import sys -import json -import errno -import subprocess - try: import configparser except ImportError: import ConfigParser as configparser +import errno +import json +import os +import re +import subprocess +import sys class VersioneerConfig: @@ -309,13 +308,11 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ( - "Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND')." - ) + err = ("Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -328,10 +325,8 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print( - "Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py) - ) + print("Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py)) except NameError: pass return root @@ -353,7 +348,6 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None - cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -378,20 +372,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -399,13 +390,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -430,9 +418,7 @@ def run_command( return stdout, p.returncode -LONG_VERSION_PY[ - "git" -] = ''' +LONG_VERSION_PY['git'] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -1007,7 +993,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1016,7 +1002,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1024,26 +1010,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -1058,9 +1037,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1068,19 +1046,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1103,18 +1072,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -1123,12 +1091,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1139,15 +1105,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1203,22 +1167,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1247,17 +1205,11 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search( - r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: - mo = re.search( - r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1266,9 +1218,8 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps( - versions, sort_keys=True, indent=1, separators=(",", ": ") - ) + contents = json.dumps(versions, sort_keys=True, + indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1300,7 +1251,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1414,13 +1366,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -1440,13 +1390,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} class VersioneerBadRootError(Exception): @@ -1469,9 +1415,8 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert ( - cfg.versionfile_source is not None - ), "please set versioneer.versionfile_source" + assert cfg.versionfile_source is not None, \ + "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1525,13 +1470,9 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, "error": "unable to compute version", + "date": None} def get_version(): @@ -1580,7 +1521,6 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1613,17 +1553,14 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join( - self.build_lib, cfg.versionfile_build - ) + target_versionfile = os.path.join(self.build_lib, + cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1644,21 +1581,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if "py2exe" in sys.modules: # py2exe enabled? + if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1677,17 +1610,13 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1714,10 +1643,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file( - target_versionfile, self._versioneer_generated_versions - ) - + write_to_version_file(target_versionfile, + self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds @@ -1772,15 +1699,11 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except ( - EnvironmentError, - configparser.NoSectionError, - configparser.NoOptionError, - ) as e: + except (EnvironmentError, configparser.NoSectionError, + configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print( - "Adding sample versioneer config to setup.cfg", file=sys.stderr - ) + print("Adding sample versioneer config to setup.cfg", + file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1789,18 +1712,15 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") + f.write(LONG % {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), + "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1842,10 +1762,8 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print( - " appending versionfile_source ('%s') to MANIFEST.in" - % cfg.versionfile_source - ) + print(" appending versionfile_source ('%s') to MANIFEST.in" % + cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From 6fcdeaeeeef1a0f8a61fc4e41d76fffbb4483e86 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 20:55:00 +0000 Subject: [PATCH 15/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- LICENSE | 2 +- ORBIT/core/cargo.py | 2 +- ORBIT/phases/design/array_system_design.py | 4 ++-- ORBIT/phases/install/oss_install/floating.py | 2 +- docs/Makefile | 2 +- library/turbines/15MW_generic.yaml | 2 +- templates/design_module.py | 10 +++++----- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/LICENSE b/LICENSE index dbb692d8..1c0c15ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index d02ab03f..843d655e 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,7 +6,7 @@ class Cargo(Object): - + def __repr__(self): return self.type diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index 6fbf911d..86ddeb6f 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -384,7 +384,7 @@ def save_layout(self, save_name, return_df=False, folder="cables"): ------- pd.DataFrame The DataFrame with the layout data. - + Raises ------ ValueError @@ -744,7 +744,7 @@ def create_project_csv(self, save_name, folder="cables"): ---------- save_name : [type] [description] - + Raises ------ ValueError diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index 6580e19a..c2d1ca2b 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -144,7 +144,7 @@ def initialize_installation_vessel(self): @property def detailed_output(self): - + return {} diff --git a/docs/Makefile b/docs/Makefile index 298ea9e2..51285967 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 50478a79..0a3683f9 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW \ No newline at end of file +turbine_rating: 15 # MW diff --git a/templates/design_module.py b/templates/design_module.py index 2b1bdafe..b308113b 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -114,13 +114,13 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library + config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above - + self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + # work with later methods. self._outputs = {} def run(self): @@ -174,7 +174,7 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in + cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @@ -267,7 +267,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" From dc2ee28065bf1d7479aedb803b9bec7463b001e9 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Wed, 1 Mar 2023 13:59:51 -0700 Subject: [PATCH 16/19] Revert "[pre-commit.ci] auto fixes from pre-commit.com hooks" This reverts commit e86ef2461e6dcf36179de0add7b6eea021a8f87d. --- LICENSE | 2 +- ORBIT/_version.py | 168 ++++------ ORBIT/api/wisdem.py | 1 + ORBIT/config.py | 1 + ORBIT/core/cargo.py | 1 + ORBIT/core/components.py | 1 + ORBIT/core/defaults/__init__.py | 1 + ORBIT/core/environment.py | 2 + ORBIT/core/exceptions.py | 1 + ORBIT/core/library.py | 2 +- ORBIT/core/logic/vessel_logic.py | 6 + ORBIT/core/port.py | 1 + ORBIT/core/supply_chain.py | 1 + ORBIT/core/vessel.py | 2 + ORBIT/manager.py | 20 +- ORBIT/parametric.py | 5 +- ORBIT/phases/base.py | 2 + ORBIT/phases/design/_cables.py | 3 +- ORBIT/phases/design/array_system_design.py | 4 + ORBIT/phases/design/export_system_design.py | 2 + ORBIT/phases/design/monopile_design.py | 7 +- ORBIT/phases/design/mooring_system_design.py | 6 +- ORBIT/phases/design/oss_design.py | 3 +- .../phases/design/scour_protection_design.py | 3 +- .../phases/design/semi_submersible_design.py | 8 +- ORBIT/phases/design/spar_design.py | 7 +- ORBIT/phases/install/cable_install/array.py | 5 + ORBIT/phases/install/cable_install/common.py | 1 + ORBIT/phases/install/cable_install/export.py | 3 +- ORBIT/phases/install/install_phase.py | 1 + ORBIT/phases/install/jacket_install/common.py | 1 + .../phases/install/jacket_install/standard.py | 9 +- .../phases/install/monopile_install/common.py | 2 + .../install/monopile_install/standard.py | 9 +- .../phases/install/mooring_install/mooring.py | 3 + ORBIT/phases/install/oss_install/common.py | 2 + ORBIT/phases/install/oss_install/floating.py | 9 +- ORBIT/phases/install/oss_install/standard.py | 3 + .../quayside_assembly_tow/gravity_base.py | 3 + .../install/quayside_assembly_tow/moored.py | 3 + .../scour_protection_install/standard.py | 1 + .../phases/install/turbine_install/common.py | 1 + .../install/turbine_install/standard.py | 4 + ORBIT/supply_chain.py | 245 +++++++------- docs/Makefile | 2 +- docs/conf.py | 4 +- library/turbines/15MW_generic.yaml | 2 +- misc/supply_chain_plots.py | 183 ++++------- templates/design_module.py | 74 ++--- tests/api/test_wisdem_api.py | 3 + tests/conftest.py | 9 + tests/core/test_environment.py | 1 + tests/core/test_library.py | 2 + tests/core/test_port.py | 3 + .../phases/design/test_array_system_design.py | 2 + tests/phases/design/test_cable.py | 2 + .../design/test_export_system_design.py | 2 + tests/phases/design/test_monopile_design.py | 6 + .../design/test_mooring_system_design.py | 5 + tests/phases/design/test_oss_design.py | 4 + .../design/test_scour_protection_design.py | 1 + .../design/test_semisubmersible_design.py | 4 + tests/phases/design/test_spar_design.py | 4 + .../cable_install/test_array_install.py | 10 + .../install/cable_install/test_cable_tasks.py | 3 + .../cable_install/test_export_install.py | 10 + .../jacket_install/test_jacket_install.py | 10 + .../monopile_install/test_monopile_install.py | 9 + .../monopile_install/test_monopile_tasks.py | 3 + .../mooring_install/test_mooring_install.py | 5 + .../install/oss_install/test_oss_install.py | 10 + .../install/oss_install/test_oss_tasks.py | 3 + .../quayside_assembly_tow/test_common.py | 4 + .../test_gravity_based.py | 3 + .../quayside_assembly_tow/test_moored.py | 3 + .../test_scour_protection.py | 5 + tests/phases/install/test_install_phase.py | 3 + .../turbine_install/test_turbine_install.py | 12 + .../turbine_install/test_turbine_tasks.py | 3 + tests/phases/test_base.py | 5 + tests/test_config_management.py | 3 + .../test_design_install_phase_interactions.py | 5 +- tests/test_parametric.py | 9 +- tests/test_project_manager.py | 44 ++- versioneer.py | 298 +++++++----------- 85 files changed, 714 insertions(+), 624 deletions(-) diff --git a/LICENSE b/LICENSE index 1c0c15ea..dbb692d8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/_version.py b/ORBIT/_version.py index f03f6681..fa1e63bc 100644 --- a/ORBIT/_version.py +++ b/ORBIT/_version.py @@ -1,3 +1,4 @@ + # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -9,11 +10,11 @@ """Git implementation of _version.py.""" +import errno import os import re -import sys -import errno import subprocess +import sys def get_keywords(): @@ -57,20 +58,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -78,13 +76,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -121,22 +116,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -192,7 +181,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -201,7 +190,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -209,26 +198,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -243,9 +225,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -253,19 +234,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -288,18 +260,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -308,12 +279,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -324,15 +293,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -363,7 +330,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -477,13 +445,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -503,13 +469,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} def get_versions(): @@ -523,9 +485,8 @@ def get_versions(): verbose = cfg.verbose try: - return git_versions_from_keywords( - get_keywords(), cfg.tag_prefix, verbose - ) + return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, + verbose) except NotThisMethod: pass @@ -534,16 +495,13 @@ def get_versions(): # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. - for i in cfg.versionfile_source.split("/"): + for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to find root of source tree", + "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) @@ -557,10 +515,6 @@ def get_versions(): except NotThisMethod: pass - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, + "error": "unable to compute version", "date": None} diff --git a/ORBIT/api/wisdem.py b/ORBIT/api/wisdem.py index 63fd1460..8320e99c 100644 --- a/ORBIT/api/wisdem.py +++ b/ORBIT/api/wisdem.py @@ -7,6 +7,7 @@ import openmdao.api as om + from ORBIT import ProjectManager diff --git a/ORBIT/config.py b/ORBIT/config.py index 5a416b43..4a50732d 100644 --- a/ORBIT/config.py +++ b/ORBIT/config.py @@ -8,6 +8,7 @@ import yaml from yaml import Dumper + from ORBIT.core import loader diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index 0f618b4e..d02ab03f 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,6 +6,7 @@ class Cargo(Object): + def __repr__(self): return self.type diff --git a/ORBIT/core/components.py b/ORBIT/core/components.py index dec26889..e4e3792c 100644 --- a/ORBIT/core/components.py +++ b/ORBIT/core/components.py @@ -6,6 +6,7 @@ __email__ = "jake.nunemaker@nrel.gov" import simpy + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, InsufficientCable diff --git a/ORBIT/core/defaults/__init__.py b/ORBIT/core/defaults/__init__.py index 1cc75bae..7df591ec 100644 --- a/ORBIT/core/defaults/__init__.py +++ b/ORBIT/core/defaults/__init__.py @@ -8,6 +8,7 @@ import os import yaml + from ORBIT.core.library import loader DIR = os.path.split(__file__)[0] diff --git a/ORBIT/core/environment.py b/ORBIT/core/environment.py index bade7d84..4654ec13 100644 --- a/ORBIT/core/environment.py +++ b/ORBIT/core/environment.py @@ -88,6 +88,7 @@ def standarize_state_inputs(self, _in): names = [] for name in list(_in.dtype.names): + if "windspeed" in name: try: val = name.split("_")[1].replace("m", "") @@ -138,6 +139,7 @@ def resolve_windspeed_constraints(self, constraints): return {**constraints, "windspeed": list(ws.values())[0]} for k, v in ws.items(): + if k == "windspeed": height = self.simplify_num(self.default_height) diff --git a/ORBIT/core/exceptions.py b/ORBIT/core/exceptions.py index ec9fa5d6..8d7d0ca4 100644 --- a/ORBIT/core/exceptions.py +++ b/ORBIT/core/exceptions.py @@ -31,6 +31,7 @@ def __init__(self, vessel, component): ) def __str__(self): + return self.message diff --git a/ORBIT/core/library.py b/ORBIT/core/library.py index c8217b15..6f771cc0 100644 --- a/ORBIT/core/library.py +++ b/ORBIT/core/library.py @@ -38,12 +38,12 @@ import yaml import pandas as pd from yaml import Dumper + from ORBIT.core.exceptions import LibraryItemNotFoundError ROOT = os.path.abspath(os.path.join(os.path.abspath(__file__), "../../..")) default_library = os.path.join(ROOT, "library") - # Need a custom loader to read in scientific notation correctly class CustomSafeLoader(yaml.SafeLoader): def construct_python_tuple(self, node): diff --git a/ORBIT/core/logic/vessel_logic.py b/ORBIT/core/logic/vessel_logic.py index daa4a707..b27a3e78 100644 --- a/ORBIT/core/logic/vessel_logic.py +++ b/ORBIT/core/logic/vessel_logic.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.defaults import process_times as pt from ORBIT.core.exceptions import ItemNotFound, MissingComponent @@ -148,6 +149,7 @@ def shuttle_items_to_queue(vessel, port, queue, distance, items, **kwargs): transit_time = vessel.transit_time(distance) while True: + if vessel.at_port: vessel.submit_debug_log(message=f"{vessel} is at port.") @@ -260,13 +262,16 @@ def get_list_of_items_from_port(vessel, port, items, **kwargs): proposed_mass = vessel.storage.current_cargo_mass + total_mass if vessel.storage.current_cargo_mass == 0: + if proposed_deck_space > vessel.storage.max_deck_space: + msg = ( f"Warning: '{vessel}' Deck Space Capacity Exceeded" ) vessel.submit_debug_log(message=msg) if proposed_mass > vessel.storage.max_cargo_mass: + msg = ( f"Warning: '{vessel}' Cargo Mass Capacity Exceeded" ) @@ -327,6 +332,7 @@ def shuttle_items_to_queue_wait( n = 0 while n < assigned: + vessel.submit_debug_log(message=f"{vessel} is at port.") # Get list of items diff --git a/ORBIT/core/port.py b/ORBIT/core/port.py index c24ccfa6..dbfc152a 100644 --- a/ORBIT/core/port.py +++ b/ORBIT/core/port.py @@ -7,6 +7,7 @@ import simpy + from ORBIT.core.exceptions import ItemNotFound diff --git a/ORBIT/core/supply_chain.py b/ORBIT/core/supply_chain.py index 6f271c9b..0f2f3e1a 100644 --- a/ORBIT/core/supply_chain.py +++ b/ORBIT/core/supply_chain.py @@ -41,6 +41,7 @@ def __init__( @process def start(self): + n = 0 while n < self.num: yield self.task( diff --git a/ORBIT/core/vessel.py b/ORBIT/core/vessel.py index c952e905..88c823a4 100644 --- a/ORBIT/core/vessel.py +++ b/ORBIT/core/vessel.py @@ -15,6 +15,7 @@ WindowNotFound, AgentNotRegistered, ) + from ORBIT.core.components import ( Crane, JackingSys, @@ -85,6 +86,7 @@ def submit_action_log(self, action, duration, **kwargs): def task_wrapper( self, name, duration, constraints={}, suspendable=False, **kwargs ): + duration /= self.avail yield self.task(name, duration, constraints, suspendable, **kwargs) diff --git a/ORBIT/manager.py b/ORBIT/manager.py index ccb0a47d..6aeb5ba1 100644 --- a/ORBIT/manager.py +++ b/ORBIT/manager.py @@ -14,9 +14,10 @@ from itertools import product import numpy as np -import ORBIT import pandas as pd from benedict import benedict + +import ORBIT from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.core.library import ( initialize_library, @@ -166,12 +167,14 @@ def run(self, **kwargs): self._print_warnings() def _print_warnings(self): + try: df = pd.DataFrame(self.logs) df = df.loc[~df["message"].isnull()] df = df.loc[df["message"].str.contains("Exceeded")] for msg in df["message"].unique(): + idx = df.loc[df["message"] == msg].index[0] phase = df.loc[idx, "phase"] print(f"{phase}:\n\t {msg}") @@ -202,9 +205,7 @@ def register_design_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._design_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -228,9 +229,7 @@ def register_install_phase(cls, phase): ) if phase.__name__ in [c.__name__ for c in cls._install_phases]: - raise ValueError( - f"A phase with name '{phase.__name__}' already exists." - ) + raise ValueError(f"A phase with name '{phase.__name__}' already exists.") if len(re.split("[_ ]", phase.__name__)) > 1: raise ValueError(f"Registered phase name must not include a '_'.") @@ -454,6 +453,7 @@ def remove_keys(cls, left, right): right = {k: right[k] for k in set(new).intersection(set(right))} for k, val in right.items(): + if isinstance(new.get(k, None), dict) and isinstance(val, dict): new[k] = cls.remove_keys(new[k], val) @@ -500,6 +500,7 @@ def create_config_for_phase(self, phase): @property def phase_ends(self): + ret = {} for k, t in self.phase_times.items(): try: @@ -692,6 +693,7 @@ def run_multiple_phases_overlapping(self, phases, **kwargs): # Run defined for name, start in defined.items(): + _, logs = self.run_install_phase(name, start, **kwargs) if logs is None: @@ -725,6 +727,7 @@ def run_dependent_phases(self, _phases, zero, **kwargs): skipped = {} while True: + phases = {**phases, **skipped} if not phases: break @@ -823,6 +826,7 @@ def _parse_install_phase_values(self, phases): depends = {} for k, v in phases.items(): + if isinstance(v, (int, float)): defined[k] = ceil(v) @@ -1100,6 +1104,7 @@ def progress_summary(self): summary = {} for i in range(1, len(self.month_bins)): + unique, counts = np.unique( arr["progress"][dig == i], return_counts=True ) @@ -1135,6 +1140,7 @@ def phase_dates(self): dates = {} for phase, _start in self.config["install_phases"].items(): + start = dt.datetime.strptime(_start, self.date_format_short) end = start + dt.timedelta(hours=ceil(self.phase_times[phase])) diff --git a/ORBIT/parametric.py b/ORBIT/parametric.py index 634b842c..6895400c 100644 --- a/ORBIT/parametric.py +++ b/ORBIT/parametric.py @@ -15,9 +15,10 @@ import pandas as pd import statsmodels.api as sm from yaml import Loader -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager + class ParametricManager: """Class for configuring parametric ORBIT runs.""" @@ -201,6 +202,7 @@ def from_config(cls, data): funcs = {} for k, v in outputs.items(): + split = v.split("[") attr = split[0] @@ -296,6 +298,7 @@ def as_string(self): out = "" for i, (k, v) in enumerate(params.items()): + if i == 0: pre = "" diff --git a/ORBIT/phases/base.py b/ORBIT/phases/base.py index 1b39d91a..2e9b539d 100644 --- a/ORBIT/phases/base.py +++ b/ORBIT/phases/base.py @@ -10,6 +10,7 @@ from copy import deepcopy from benedict import benedict + from ORBIT.core.library import initialize_library, extract_library_data from ORBIT.core.exceptions import MissingInputs @@ -69,6 +70,7 @@ def _check_keys(cls, expected, config): missing = [] for k, v in expected.items(): + if isinstance(k, str) and "variable" in k: continue diff --git a/ORBIT/phases/design/_cables.py b/ORBIT/phases/design/_cables.py index 1b93d209..27343a58 100644 --- a/ORBIT/phases/design/_cables.py +++ b/ORBIT/phases/design/_cables.py @@ -11,6 +11,7 @@ import numpy as np from scipy.optimize import fsolve + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import DesignPhase @@ -332,7 +333,7 @@ def _get_touchdown_distance(self): else: self.touchdown = depth * 0.3 - # TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water + #TODO: Update this scaling function - should be closer to cable bend radius. Unrealistic for deep water @staticmethod def _catenary(a, *data): diff --git a/ORBIT/phases/design/array_system_design.py b/ORBIT/phases/design/array_system_design.py index c109a7fa..be00adbb 100644 --- a/ORBIT/phases/design/array_system_design.py +++ b/ORBIT/phases/design/array_system_design.py @@ -12,6 +12,7 @@ import numpy as np import pandas as pd import matplotlib.pyplot as plt + from ORBIT.core.library import export_library_specs, extract_library_specs from ORBIT.phases.design._cables import Plant, CableSystem @@ -566,6 +567,7 @@ def plot_array_system( for i, row in enumerate(self.sections_cables): for cable, width in zip(max_string, string_widths): + ix_to_plot = np.where(row == cable)[0] if ix_to_plot.size == 0: continue @@ -793,6 +795,7 @@ def create_project_csv(self, save_name): export_library_specs("cables", save_name, rows, file_ext="csv") def _format_windfarm_data(self): + # Separate the OSS data where substaion_id is equal to id substation_filter = ( self.location_data.substation_id == self.location_data.id @@ -1036,6 +1039,7 @@ def _create_windfarm_layout(self): self.sections_distance = self._compute_haversine_distance() def run(self): + self._initialize_cables() self.create_strings() self._initialize_custom_data() diff --git a/ORBIT/phases/design/export_system_design.py b/ORBIT/phases/design/export_system_design.py index bf7af015..6c6ae0a0 100644 --- a/ORBIT/phases/design/export_system_design.py +++ b/ORBIT/phases/design/export_system_design.py @@ -6,6 +6,7 @@ __email__ = "robert.hammond@nrel.gov" import numpy as np + from ORBIT.phases.design._cables import CableSystem @@ -212,6 +213,7 @@ def design_result(self): } for name, cable in self.cables.items(): + output["export_system"]["cable"] = { "linear_density": cable.linear_density, "sections": [self.length], diff --git a/ORBIT/phases/design/monopile_design.py b/ORBIT/phases/design/monopile_design.py index 082b3a9c..ab1e5349 100644 --- a/ORBIT/phases/design/monopile_design.py +++ b/ORBIT/phases/design/monopile_design.py @@ -9,6 +9,7 @@ from math import pi, log from scipy.optimize import fsolve + from ORBIT.core.defaults import common_costs from ORBIT.phases.design import DesignPhase @@ -229,7 +230,7 @@ def design_transition_piece(self, D_p, t_p, **kwargs): "diameter": D_tp, "mass": m_tp, "length": L_tp, - "deck_space": D_tp**2, + "deck_space": D_tp ** 2, "unit_cost": m_tp * self.tp_steel_cost, } @@ -354,7 +355,7 @@ def pile_mass(Dp, tp, Lt, **kwargs): """ density = kwargs.get("monopile_density", 7860) # kg/m3 - volume = (pi / 4) * (Dp**2 - (Dp - tp) ** 2) * Lt + volume = (pi / 4) * (Dp ** 2 - (Dp - tp) ** 2) * Lt mass = density * volume / 907.185 return mass @@ -559,7 +560,7 @@ def calculate_thrust_coefficient(rated_windspeed): """ ct = min( - [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed**2), 1] + [3.5 * (2 * rated_windspeed + 3.5) / (rated_windspeed ** 2), 1] ) return ct diff --git a/ORBIT/phases/design/mooring_system_design.py b/ORBIT/phases/design/mooring_system_design.py index 0dcf67d8..383a4924 100644 --- a/ORBIT/phases/design/mooring_system_design.py +++ b/ORBIT/phases/design/mooring_system_design.py @@ -76,7 +76,7 @@ def determine_mooring_line(self): """ tr = self.config["turbine"]["turbine_rating"] - fit = -0.0004 * (tr**2) + 0.0132 * tr + 0.0536 + fit = -0.0004 * (tr ** 2) + 0.0132 * tr + 0.0536 if fit <= 0.09: self.line_diam = 0.09 @@ -99,7 +99,7 @@ def calculate_breaking_load(self): """ self.breaking_load = ( - 419449 * (self.line_diam**2) + 93415 * self.line_diam - 3577.9 + 419449 * (self.line_diam ** 2) + 93415 * self.line_diam - 3577.9 ) def calculate_line_length_mass(self): @@ -115,7 +115,7 @@ def calculate_line_length_mass(self): depth = self.config["site"]["depth"] self.line_length = ( - 0.0002 * (depth**2) + 1.264 * depth + 47.776 + fixed + 0.0002 * (depth ** 2) + 1.264 * depth + 47.776 + fixed ) self.line_mass = self.line_length * self.line_mass_per_m diff --git a/ORBIT/phases/design/oss_design.py b/ORBIT/phases/design/oss_design.py index ea72c993..1a2fe071 100644 --- a/ORBIT/phases/design/oss_design.py +++ b/ORBIT/phases/design/oss_design.py @@ -7,6 +7,7 @@ import numpy as np + from ORBIT.phases.design import DesignPhase @@ -283,7 +284,7 @@ def calc_substructure_mass_and_cost(self): oss_pile_cost_rate = _design.get("oss_pile_cost_rate", 0) substructure_mass = 0.4 * self.topside_mass - substructure_pile_mass = 8 * substructure_mass**0.5574 + substructure_pile_mass = 8 * substructure_mass ** 0.5574 self.substructure_cost = ( substructure_mass * oss_substructure_cost_rate + substructure_pile_mass * oss_pile_cost_rate diff --git a/ORBIT/phases/design/scour_protection_design.py b/ORBIT/phases/design/scour_protection_design.py index d36b91eb..efa66b4f 100644 --- a/ORBIT/phases/design/scour_protection_design.py +++ b/ORBIT/phases/design/scour_protection_design.py @@ -8,6 +8,7 @@ from math import ceil import numpy as np + from ORBIT.phases.design import DesignPhase @@ -114,7 +115,7 @@ def compute_scour_protection_tonnes_to_install(self): r = self.diameter / 2 + self.scour_depth / np.tan(np.radians(self.phi)) volume = ( - np.pi * self.protection_depth * (r**2 - (self.diameter / 2) ** 2) + np.pi * self.protection_depth * (r ** 2 - (self.diameter / 2) ** 2) ) self.scour_protection_tonnes = ceil( diff --git a/ORBIT/phases/design/semi_submersible_design.py b/ORBIT/phases/design/semi_submersible_design.py index 7bb34217..58404a29 100644 --- a/ORBIT/phases/design/semi_submersible_design.py +++ b/ORBIT/phases/design/semi_submersible_design.py @@ -67,7 +67,7 @@ def stiffened_column_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.9581 * rating**2 + 40.89 * rating + 802.09 + mass = -0.9581 * rating ** 2 + 40.89 * rating + 802.09 return mass @@ -89,7 +89,7 @@ def truss_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = 2.7894 * rating**2 + 15.591 * rating + 266.03 + mass = 2.7894 * rating ** 2 + 15.591 * rating + 266.03 return mass @@ -111,7 +111,7 @@ def heave_plate_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.4397 * rating**2 + 21.545 * rating + 177.42 + mass = -0.4397 * rating ** 2 + 21.545 * rating + 177.42 return mass @@ -133,7 +133,7 @@ def secondary_steel_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -0.153 * rating**2 + 6.54 * rating + 128.34 + mass = -0.153 * rating ** 2 + 6.54 * rating + 128.34 return mass diff --git a/ORBIT/phases/design/spar_design.py b/ORBIT/phases/design/spar_design.py index c8b0862e..224c4a5e 100644 --- a/ORBIT/phases/design/spar_design.py +++ b/ORBIT/phases/design/spar_design.py @@ -7,6 +7,7 @@ from numpy import exp, log + from ORBIT.phases.design import DesignPhase @@ -71,7 +72,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -112,7 +113,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -137,7 +138,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) diff --git a/ORBIT/phases/install/cable_install/array.py b/ORBIT/phases/install/cable_install/array.py index 21120126..d4d8a181 100644 --- a/ORBIT/phases/install/cable_install/array.py +++ b/ORBIT/phases/install/cable_install/array.py @@ -10,6 +10,7 @@ import numpy as np from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase @@ -236,6 +237,7 @@ def install_array_cables( trench_vessel.at_site = True elif trench_vessel.at_site: + try: # Dig trench along each cable section distance trench_distance = trench_sections.pop(0) @@ -267,6 +269,7 @@ def install_array_cables( vessel.at_site = True elif vessel.at_site: + try: length, num_sections, *extra = sections.pop(0) if extra: @@ -288,10 +291,12 @@ def install_array_cables( break for _ in range(num_sections): + try: section = vessel.cable_storage.get_cable(length) except InsufficientCable: + yield vessel.transit(distance, **kwargs) yield load_cable_on_vessel(vessel, cable, **kwargs) yield vessel.transit(distance, **kwargs) diff --git a/ORBIT/phases/install/cable_install/common.py b/ORBIT/phases/install/cable_install/common.py index fa0833f2..f2481138 100644 --- a/ORBIT/phases/install/cable_install/common.py +++ b/ORBIT/phases/install/cable_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/cable_install/export.py b/ORBIT/phases/install/cable_install/export.py index 55bf7d32..486bc9e7 100644 --- a/ORBIT/phases/install/cable_install/export.py +++ b/ORBIT/phases/install/cable_install/export.py @@ -10,6 +10,7 @@ from math import ceil from marmot import process + from ORBIT.core.logic import position_onsite from ORBIT.phases.install import InstallPhase from ORBIT.core.exceptions import InsufficientCable @@ -182,7 +183,7 @@ def calculate_onshore_transmission_cost(self, **kwargs): onshore_substation_cost = ( 0.165 * 1e6 ) * capacity # From BNEF Tomorrow's Cost of Offshore Wind - onshore_misc_cost = 11795 * capacity**0.3549 + 350000 + onshore_misc_cost = 11795 * capacity ** 0.3549 + 350000 transmission_line_cost = (1176 * voltage + 218257) * ( distance ** (1 - 0.1063) ) diff --git a/ORBIT/phases/install/install_phase.py b/ORBIT/phases/install/install_phase.py index c4d159d6..97b93c3b 100644 --- a/ORBIT/phases/install/install_phase.py +++ b/ORBIT/phases/install/install_phase.py @@ -12,6 +12,7 @@ import numpy as np import simpy import pandas as pd + from ORBIT.core import Port, Vessel, Environment from ORBIT.phases import BasePhase from ORBIT.core.defaults import common_costs diff --git a/ORBIT/phases/install/jacket_install/common.py b/ORBIT/phases/install/jacket_install/common.py index 5cd9feb2..4312bfcf 100644 --- a/ORBIT/phases/install/jacket_install/common.py +++ b/ORBIT/phases/install/jacket_install/common.py @@ -5,6 +5,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/jacket_install/standard.py b/ORBIT/phases/install/jacket_install/standard.py index 10391d6e..2f8f0c55 100644 --- a/ORBIT/phases/install/jacket_install/standard.py +++ b/ORBIT/phases/install/jacket_install/standard.py @@ -7,6 +7,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -110,7 +111,9 @@ def system_capex(self): ] def initialize_substructure_delivery(self): - """ """ + """ + + """ jacket = Jacket(**self.config["jacket"]) @@ -129,6 +132,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("jacket_supply_chain", {}) if self.supply_chain.get("enabled", False): + items = [jacket, self.tp] if self.tp else [jacket] delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 @@ -369,6 +373,7 @@ def solo_install_jackets( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for jacket install yield prep_for_site_operations( @@ -433,7 +438,9 @@ def install_jackets_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for jacket install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/monopile_install/common.py b/ORBIT/phases/install/monopile_install/common.py index ee1fcb74..04af017a 100644 --- a/ORBIT/phases/install/monopile_install/common.py +++ b/ORBIT/phases/install/monopile_install/common.py @@ -7,6 +7,7 @@ from marmot import false, process + from ORBIT.core import Cargo from ORBIT.core.logic import jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -339,6 +340,7 @@ def install_transition_piece(vessel, tp, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel) diff --git a/ORBIT/phases/install/monopile_install/standard.py b/ORBIT/phases/install/monopile_install/standard.py index 02c7c259..5a204709 100644 --- a/ORBIT/phases/install/monopile_install/standard.py +++ b/ORBIT/phases/install/monopile_install/standard.py @@ -9,6 +9,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import SubstructureDelivery from ORBIT.core.logic import ( prep_for_site_operations, @@ -105,7 +106,9 @@ def system_capex(self): ) * self.config["plant"]["num_turbines"] def initialize_substructure_delivery(self): - """ """ + """ + + """ monopile = Monopile(**self.config["monopile"]) tp = TransitionPiece(**self.config["transition_piece"]) @@ -116,6 +119,7 @@ def initialize_substructure_delivery(self): self.supply_chain = self.config.get("monopile_supply_chain", {}) if self.supply_chain.get("enabled", False): + delivery_time = self.supply_chain.get( "substructure_delivery_time", 168 ) @@ -342,6 +346,7 @@ def solo_install_monopiles(vessel, port, distance, monopiles, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: # Prep for monopile install yield prep_for_site_operations( @@ -403,7 +408,9 @@ def install_monopiles_from_queue(wtiv, queue, monopiles, distance, **kwargs): wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( wtiv, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/mooring_install/mooring.py b/ORBIT/phases/install/mooring_install/mooring.py index c4175f28..3b3573b9 100644 --- a/ORBIT/phases/install/mooring_install/mooring.py +++ b/ORBIT/phases/install/mooring_install/mooring.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo, Vessel from ORBIT.core.logic import position_onsite, get_list_of_items_from_port from ORBIT.core.defaults import process_times as pt @@ -160,7 +161,9 @@ def install_mooring_systems(vessel, port, distance, depth, systems, **kwargs): vessel.at_site = True if vessel.at_site: + if vessel.storage.items: + system = yield vessel.get_item_from_storage( "MooringSystem", **kwargs ) diff --git a/ORBIT/phases/install/oss_install/common.py b/ORBIT/phases/install/oss_install/common.py index f1c5527b..f90128ac 100644 --- a/ORBIT/phases/install/oss_install/common.py +++ b/ORBIT/phases/install/oss_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.logic import stabilize, jackdown_if_required from ORBIT.core.defaults import process_times as pt @@ -138,6 +139,7 @@ def install_topside(vessel, topside, **kwargs): yield bolt_transition_piece(vessel, **kwargs) elif connection == "grouted": + yield pump_transition_piece_grout(vessel, **kwargs) yield cure_transition_piece_grout(vessel, **kwargs) diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index a293363d..6580e19a 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -6,10 +6,11 @@ __email__ = "jake.nunemaker@nrel.gov" -from marmot import Agent, le, process +from marmot import Agent, process, le +from marmot._exceptions import AgentNotRegistered + from ORBIT.core import WetStorage from ORBIT.core.logic import position_onsite -from marmot._exceptions import AgentNotRegistered from ORBIT.phases.install import InstallPhase from ORBIT.phases.install.mooring_install.mooring import ( install_mooring_line, @@ -143,6 +144,7 @@ def initialize_installation_vessel(self): @property def detailed_output(self): + return {} @@ -173,6 +175,7 @@ def install_floating_substations( travel_time = distance / towing_speed for _ in range(number): + start = vessel.env.now yield feed.get() delay = vessel.env.now - start @@ -193,7 +196,7 @@ def install_floating_substations( constraints={"windspeed": le(15), "waveheight": le(2.5)}, ) - for _ in range(3): + for _ in range (3): yield perform_mooring_site_survey(vessel) yield install_mooring_anchor(vessel, depth, "Suction Pile") yield install_mooring_line(vessel, depth) diff --git a/ORBIT/phases/install/oss_install/standard.py b/ORBIT/phases/install/oss_install/standard.py index 15bcbd79..04038af9 100644 --- a/ORBIT/phases/install/oss_install/standard.py +++ b/ORBIT/phases/install/oss_install/standard.py @@ -8,6 +8,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import shuttle_items_to_queue, prep_for_site_operations from ORBIT.phases.install import InstallPhase @@ -229,7 +230,9 @@ def install_oss_from_queue(vessel, queue, substations, distance, **kwargs): vessel.at_site = True if vessel.at_site: + if queue.vessel: + # Prep for monopile install yield prep_for_site_operations( vessel, survey_required=True, **kwargs diff --git a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py index a02a3547..4cbd97f6 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py +++ b/ORBIT/phases/install/quayside_assembly_tow/gravity_base.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -292,6 +293,7 @@ def transfer_gbf_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -355,6 +357,7 @@ def install_gravity_base_foundations( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/quayside_assembly_tow/moored.py b/ORBIT/phases/install/quayside_assembly_tow/moored.py index 8376b274..c38908b2 100644 --- a/ORBIT/phases/install/quayside_assembly_tow/moored.py +++ b/ORBIT/phases/install/quayside_assembly_tow/moored.py @@ -8,6 +8,7 @@ import simpy from marmot import le, process + from ORBIT.core import Vessel, WetStorage from ORBIT.phases.install import InstallPhase @@ -291,6 +292,7 @@ def transfer_moored_substructures_from_storage( transit_time = distance / group.transit_speed while True: + start = group.env.now assembly = yield feed.get() delay = group.env.now - start @@ -364,6 +366,7 @@ def install_moored_substructures( n = 0 while n < substructures: if queue.vessel: + start = vessel.env.now if n == 0: vessel.mobilize() diff --git a/ORBIT/phases/install/scour_protection_install/standard.py b/ORBIT/phases/install/scour_protection_install/standard.py index db1c8ce6..9dd3ee9a 100644 --- a/ORBIT/phases/install/scour_protection_install/standard.py +++ b/ORBIT/phases/install/scour_protection_install/standard.py @@ -10,6 +10,7 @@ import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.defaults import process_times as pt from ORBIT.phases.install import InstallPhase diff --git a/ORBIT/phases/install/turbine_install/common.py b/ORBIT/phases/install/turbine_install/common.py index f65aa7a3..057ff1bd 100644 --- a/ORBIT/phases/install/turbine_install/common.py +++ b/ORBIT/phases/install/turbine_install/common.py @@ -7,6 +7,7 @@ from marmot import process + from ORBIT.core import Cargo from ORBIT.core.defaults import process_times as pt diff --git a/ORBIT/phases/install/turbine_install/standard.py b/ORBIT/phases/install/turbine_install/standard.py index 58e273ab..d23515a1 100644 --- a/ORBIT/phases/install/turbine_install/standard.py +++ b/ORBIT/phases/install/turbine_install/standard.py @@ -12,6 +12,7 @@ import numpy as np import simpy from marmot import process + from ORBIT.core import Vessel from ORBIT.core.logic import ( jackdown_if_required, @@ -320,6 +321,7 @@ def solo_install_turbines( vessel.at_site = True if vessel.at_site: + if vessel.storage.items: yield prep_for_site_operations(vessel, **kwargs) @@ -405,7 +407,9 @@ def install_turbine_components_from_queue( wtiv.at_site = True if wtiv.at_site: + if queue.vessel: + # Prep for turbine install yield prep_for_site_operations(wtiv, **kwargs) diff --git a/ORBIT/supply_chain.py b/ORBIT/supply_chain.py index 8290eae7..b17e2ae8 100644 --- a/ORBIT/supply_chain.py +++ b/ORBIT/supply_chain.py @@ -5,47 +5,71 @@ from copy import deepcopy - -from ORBIT import ProjectManager from benedict import benedict +from ORBIT import ProjectManager -DEFAULT_MULTIPLIERS = { - "blades": {"domestic": 0.026, "imported": 0.30}, - "nacelle": {"domestic": 0.025, "imported": 0.10}, - "tower": { - "domestic": 0.04, - "imported": 0.20, - "tariffs": 0.25, - }, - "monopile": { - "domestic": 0.085, - "imported": 0.28, - "tariffs": 0.25, - }, - "transition_piece": { - "domestic": 0.169, - "imported": 0.17, - "tariffs": 0.25, - }, - "array_cable": {"domestic": 0.19, "imported": 0.0}, - "export_cable": {"domestic": 0.231, "imported": 0.0}, - "oss_topside": {"domestic": 0.0, "imported": 0.0}, - "oss_substructure": {"domestic": 0.0, "imported": 0.0}, -} -TURBINE_CAPEX_SPLIT = {"blades": 0.135, "nacelle": 0.274, "tower": 0.162} +DEFAULT_MULTIPLIERS = { + "blades": { + "domestic": .026, + "imported": .30 + }, + "nacelle": { + "domestic": .025, + "imported": .10 + }, + "tower": { + "domestic": .04, + "imported": .20, + "tariffs": .25, + }, + "monopile": { + "domestic": .085, + "imported": .28, + "tariffs": .25, + }, + "transition_piece": { + "domestic": .169, + "imported": .17, + "tariffs": .25, + }, + "array_cable": { + "domestic": .19, + "imported": 0. + }, + "export_cable": { + "domestic": .231, + "imported": 0. + }, + "oss_topside": { + "domestic": 0., + "imported": 0. + }, + "oss_substructure": { + "domestic": 0., + "imported": 0. + }, + } + + +TURBINE_CAPEX_SPLIT = { + "blades": 0.135, + "nacelle": 0.274, + "tower": 0.162 +} LABOR_SPLIT = { "tower": 0.5, "monopile": 0.5, "transition_piece": 0.5, - "oss_topside": 0.5, + "oss_topside": 0.5 } class SupplyChainManager: + def __init__(self, supply_chain_configuration, **kwargs): """ Creates an instance of `SupplyChainManager`. @@ -87,17 +111,17 @@ def pre_process(self, config): """""" # Save original plant design - plant = deepcopy(config["plant"]) + plant = deepcopy(config['plant']) # Run ProjectManager without install phases to generate design results - install_phases = config["install_phases"] - config["install_phases"] = [] + install_phases = config['install_phases'] + config['install_phases'] = [] project = ProjectManager(config) project.run() config = deepcopy(project.config) # Replace calculated plant design with original - config["plant"] = plant + config['plant'] = plant # Run pre ORBIT supply chain adjustments config = self.process_turbine_capex(config) @@ -106,8 +130,8 @@ def pre_process(self, config): config = self.process_offshore_substation_topside_capex(config) # Add install phases back in - config["install_phases"] = install_phases - config["design_phases"] = [] + config['install_phases'] = install_phases + config['design_phases'] = [] return config @@ -130,51 +154,45 @@ def process_turbine_capex(self, config): ORBIT configuration. """ - blade_scenario = self.sc_config["blades"] - nacelle_scenario = self.sc_config["nacelle"] - tower_scenario = self.sc_config["blades"] + blade_scenario = self.sc_config['blades'] + nacelle_scenario = self.sc_config['nacelle'] + tower_scenario = self.sc_config['blades'] blade_mult = self.multipliers["blades"].get(blade_scenario, None) if blade_mult == None: - print( - f"Warning: scenario '{blade_scenario}' not found for category 'blades'." - ) - blade_mult = 0.0 + print(f"Warning: scenario '{blade_scenario}' not found for category 'blades'.") + blade_mult = 0. nacelle_mult = self.multipliers["nacelle"].get(nacelle_scenario, None) if nacelle_mult == None: - print( - f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'." - ) - nacelle_mult = 0.0 + print(f"Warning: scenario '{nacelle_scenario}' not found for category 'nacelle'.") + nacelle_mult = 0. - raw_cost = config.get("project_parameters.turbine_capex", 1300) - blade_adder = raw_cost * self.turbine_split["blades"] * blade_mult - nacelle_adder = raw_cost * self.turbine_split["nacelle"] * nacelle_mult + raw_cost = config.get('project_parameters.turbine_capex', 1300) + blade_adder = raw_cost * self.turbine_split['blades'] * blade_mult + nacelle_adder = raw_cost * self.turbine_split['nacelle'] * nacelle_mult if tower_scenario == "domestic, imported steel": tower_adder = self.multipliers["tower"]["domestic"] * raw_cost - tower_tariffs = ( - raw_cost - * self.turbine_split["tower"] - * (1 - self.labor_split["tower"]) - * self.multipliers["tower"]["tariffs"] - ) + tower_tariffs = raw_cost * self.turbine_split['tower'] *\ + (1 - self.labor_split['tower']) * self.multipliers["tower"]['tariffs'] else: - tower_tariffs = 0.0 + tower_tariffs = 0. tower_mult = self.multipliers["tower"].get(tower_scenario, None) if tower_mult == None: - print( - f"Warning: scenario '{tower_scenario}' not found for category 'tower'." - ) - tower_mult = 0.0 + print(f"Warning: scenario '{tower_scenario}' not found for category 'tower'.") + tower_mult = 0. - tower_adder = raw_cost * self.turbine_split["tower"] * tower_mult + tower_adder = raw_cost * self.turbine_split['tower'] * tower_mult - config["project_parameters.turbine_capex"] = sum( - [raw_cost, blade_adder, nacelle_adder, tower_adder, tower_tariffs] - ) + config['project_parameters.turbine_capex'] = sum([ + raw_cost, + blade_adder, + nacelle_adder, + tower_adder, + tower_tariffs + ]) return config @@ -188,29 +206,28 @@ def process_monopile_capex(self, config): ORBIT configuration. """ - raw_cost = config["monopile.unit_cost"] - scenario = self.sc_config["monopile"] + raw_cost = config['monopile.unit_cost'] + scenario = self.sc_config['monopile'] if scenario == "domestic, imported steel": - adder = self.multipliers["monopile"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["monopile"]) - * self.multipliers["monopile"]["tariffs"] - ) + adder = self.multipliers['monopile']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['monopile']) *\ + self.multipliers["monopile"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["monopile"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'monopile'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'monopile'.") + mult = 0. adder = raw_cost * mult - config["monopile.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['monopile.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -225,29 +242,28 @@ def process_transition_piece_capex(self, config): ORBIT configuration. """ - raw_cost = config["transition_piece.unit_cost"] - scenario = self.sc_config["transition_piece"] + raw_cost = config['transition_piece.unit_cost'] + scenario = self.sc_config['transition_piece'] if scenario == "domestic, imported steel": - adder = self.multipliers["transition_piece"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["transition_piece"]) - * self.multipliers["transition_piece"]["tariffs"] - ) + adder = self.multipliers['transition_piece']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['transition_piece']) *\ + self.multipliers["transition_piece"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["transition_piece"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'transition_piece'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'transition_piece'.") + mult = 0. adder = raw_cost * mult - config["transition_piece.unit_cost"] = sum([raw_cost, adder, tariffs]) + config['transition_piece.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -262,31 +278,28 @@ def process_offshore_substation_topside_capex(self, config): ORBIT configuration. """ - raw_cost = config["offshore_substation_topside.unit_cost"] - scenario = self.sc_config["oss_topside"] + raw_cost = config['offshore_substation_topside.unit_cost'] + scenario = self.sc_config['oss_topside'] if scenario == "domestic, imported steel": - adder = self.multipliers["oss_topside"]["domestic"] * raw_cost - tariffs = ( - raw_cost - * (1 - self.labor_split["oss_topside"]) - * self.multipliers["oss_topside"]["tariffs"] - ) + adder = self.multipliers['oss_topside']['domestic'] * raw_cost + tariffs = raw_cost * (1 - self.labor_split['oss_topside']) *\ + self.multipliers["oss_topside"]['tariffs'] else: - tariffs = 0.0 + tariffs = 0. mult = self.multipliers["oss_topside"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'oss_topside'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'oss_topside'.") + mult = 0. adder = raw_cost * mult - config["offshore_substation_topside.unit_cost"] = sum( - [raw_cost, adder, tariffs] - ) + config['offshore_substation_topside.unit_cost'] = sum([ + raw_cost, + adder, + tariffs + ]) return config @@ -300,15 +313,13 @@ def process_array_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["array_cable"] + scenario = self.sc_config['array_cable'] mult = self.multipliers["array_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'array_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'array_cable'.") + mult = 0. - project.system_costs["ArrayCableInstallation"] *= 1 + mult + project.system_costs['ArrayCableInstallation'] *= (1 + mult) return project @@ -321,14 +332,12 @@ def process_export_cable_capex(self, project): project : ProjectManager """ - scenario = self.sc_config["export_cable"] + scenario = self.sc_config['export_cable'] mult = self.multipliers["export_cable"].get(scenario, None) if mult == None: - print( - f"Warning: scenario '{scenario}' not found for category 'export_cable'." - ) - mult = 0.0 + print(f"Warning: scenario '{scenario}' not found for category 'export_cable'.") + mult = 0. - project.system_costs["ExportCableInstallation"] *= 1 + mult + project.system_costs['ExportCableInstallation'] *= (1 + mult) return project diff --git a/docs/Makefile b/docs/Makefile index 51285967..298ea9e2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 555a6637..38ceb207 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,10 +11,10 @@ import os import sys -import ORBIT - sys.path.insert(0, os.path.abspath("..")) +import ORBIT + # -- Project information ----------------------------------------------------- project = "ORBIT" diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 0a3683f9..50478a79 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW +turbine_rating: 15 # MW \ No newline at end of file diff --git a/misc/supply_chain_plots.py b/misc/supply_chain_plots.py index 00a13ba3..75b6fd5c 100644 --- a/misc/supply_chain_plots.py +++ b/misc/supply_chain_plots.py @@ -1,40 +1,31 @@ -import os +import pandas as pd import math - import numpy as np -import pandas as pd import matplotlib as mpl -import matplotlib.text as txt import matplotlib.pyplot as plt +import matplotlib.text as txt +import os - -def mysave(fig, froot, mode="png"): - assert mode in ["png", "eps", "pdf", "all"] +def mysave(fig, froot, mode='png'): + assert mode in ['png', 'eps', 'pdf', 'all'] fileName, fileExtension = os.path.splitext(froot) padding = 0.1 dpiVal = 200 legs = [] for a in fig.get_axes(): addLeg = a.get_legend() - if not addLeg is None: - legs.append(a.get_legend()) + if not addLeg is None: legs.append(a.get_legend()) ext = [] - if mode == "png" or mode == "all": - ext.append("png") - if mode == "eps": # or mode == 'all': - ext.append("eps") - if mode == "pdf" or mode == "all": - ext.append("pdf") + if mode == 'png' or mode == 'all': + ext.append('png') + if mode == 'eps': # or mode == 'all': + ext.append('eps') + if mode == 'pdf' or mode == 'all': + ext.append('pdf') for sfx in ext: - fig.savefig( - fileName + "." + sfx, - format=sfx, - pad_inches=padding, - bbox_inches="tight", - dpi=dpiVal, - bbox_extra_artists=legs, - ) + fig.savefig(fileName + '.' + sfx, format=sfx, pad_inches=padding, bbox_inches='tight', + dpi=dpiVal, bbox_extra_artists=legs) titleSize = 24 # 40 #38 @@ -47,48 +38,32 @@ def mysave(fig, froot, mode="png"): linewidth = 3 -def myformat( - ax, - linewidth=linewidth, - xticklabel=tickLabelSize, - yticklabel=tickLabelSize, - mode="save", -): - assert type(mode) == type("") - assert mode.lower() in ["save", "show"], "Unknown mode" - - def myformat( - myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel - ): - if mode.lower() == "show": +def myformat(ax, linewidth=linewidth, xticklabel=tickLabelSize, yticklabel=tickLabelSize, mode='save'): + assert type(mode) == type('') + assert mode.lower() in ['save', 'show'], 'Unknown mode' + + def myformat(myax, linewidth=linewidth, xticklabel=xticklabel, yticklabel=yticklabel): + if mode.lower() == 'show': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize + 3 * deltaShow) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize + deltaShow + 6) + for t in leg.get_texts(): t.set_fontsize(legendSize + deltaShow + 6) th = leg.get_title() if not th is None: th.set_fontsize(legendSize + deltaShow + 6) - myax.set_title( - myax.get_title(), size=titleSize + deltaShow, weight="bold" - ) - myax.set_xlabel( - myax.get_xlabel(), size=axLabelSize + deltaShow, weight="bold" - ) - myax.set_ylabel( - myax.get_ylabel(), size=axLabelSize + deltaShow, weight="bold" - ) + myax.set_title(myax.get_title(), size=titleSize + deltaShow, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize + deltaShow, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize + deltaShow, weight='bold') myax.tick_params(labelsize=tickLabelSize + deltaShow) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -100,29 +75,27 @@ def myformat( for i in myax.get_yticklines(): i.set_linewidth(3) - elif mode.lower() == "save": + elif mode.lower() == 'save': for i in myax.get_children(): # Gets EVERYTHING! if isinstance(i, txt.Text): i.set_size(textSize) for i in myax.get_lines(): - if i.get_marker() == "D": - continue # Don't modify baseline diamond + if i.get_marker() == 'D': continue # Don't modify baseline diamond i.set_linewidth(linewidth) # i.set_markeredgewidth(4) i.set_markersize(10) leg = myax.get_legend() if not leg is None: - for t in leg.get_texts(): - t.set_fontsize(legendSize) + for t in leg.get_texts(): t.set_fontsize(legendSize) th = leg.get_title() if not th is None: th.set_fontsize(legendSize) - myax.set_title(myax.get_title(), size=titleSize, weight="bold") - myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight="bold") - myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight="bold") + myax.set_title(myax.get_title(), size=titleSize, weight='bold') + myax.set_xlabel(myax.get_xlabel(), size=axLabelSize, weight='bold') + myax.set_ylabel(myax.get_ylabel(), size=axLabelSize, weight='bold') myax.tick_params(labelsize=tickLabelSize) myax.patch.set_linewidth(3) for i in myax.get_xticklabels(): @@ -135,62 +108,40 @@ def myformat( i.set_linewidth(3) if type(ax) == type([]): - for i in ax: - myformat(i) + for i in ax: myformat(i) else: myformat(ax) - def initFigAxis(figx=12, figy=9): fig = plt.figure(figsize=(figx, figy)) ax = fig.add_subplot(111) return fig, ax - def waterfall_plot(x, y, bottom, color, bar_text, fname=None): - """Waterfall plot comparing European andUS manufactining costs""" + """ Waterfall plot comparing European andUS manufactining costs""" fig, ax = initFigAxis() - h = ax.bar(x, y, bottom=bottom, color=color, edgecolor="k") + h = ax.bar(x, y,bottom=bottom, color=color, edgecolor='k') ax.get_yaxis().set_major_formatter( - mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ",")) - ) - ax.set_ylabel("Capital Expenditures, $/kW") - ax.set_title( - "Comparison of different cost premiums between \nimported and domestically manufactured components" - ) - - h[3].set_linestyle("--") + mpl.ticker.FuncFormatter(lambda x, p: format(int(x), ','))) + ax.set_ylabel('Capital Expenditures, $/kW') + ax.set_title('Comparison of different cost premiums between \nimported and domestically manufactured components') + + h[3].set_linestyle('--') h[3].set_linewidth(1.75) - h[3].set_edgecolor("k") - - ax.text( - x[1], - 2000, - bar_text["transit"], - horizontalalignment="center", - ) - ax.text( - x[2], - 2000, - bar_text["factory"], - horizontalalignment="center", - ) - ax.text( - x[3], - 2000, - bar_text["margin"], - horizontalalignment="center", - ) + h[3].set_edgecolor('k') + + ax.text(x[1], 2000, bar_text['transit'], horizontalalignment='center',) + ax.text(x[2], 2000, bar_text['factory'], horizontalalignment='center',) + ax.text(x[3], 2000, bar_text['margin'], horizontalalignment='center',) if fname is not None: myformat(ax) mysave(fig, fname) plt.close() - def area_time_plot(x, y, color, fname=None): """Area plot showing changin component cost over time""" @@ -199,52 +150,40 @@ def area_time_plot(x, y, color, fname=None): y0 = np.zeros(len(x)) y_init = 0 - y_init = np.sum([v[0] for k, v in y.items()]) + y_init = np.sum([v[0] for k,v in y.items()]) - for k, v in y.items(): - y1 = [yi + vi for yi, vi in zip(y0, v)] + for k,v in y.items(): + y1 = [yi+vi for yi, vi in zip(y0,v)] ax.fill_between(x, y0 / y_init, y1 / y_init, color=color[k], label=k) - ax.plot(x, y1 / y_init, "w") + ax.plot(x, y1 / y_init, 'w') y0 = y1 # Define margin - ax.fill_between( - x, - y1 / y_init, - np.ones(len(x)), - color=color["Cost margin"], - label="Margin", - ) + ax.fill_between(x, y1 / y_init, np.ones(len(x)), color=color['Cost margin'], label='Margin') - final_margin = round(100 * (1 - y1[-1] / y_init), 1) + final_margin = round( 100* (1 - y1[-1] / y_init), 1) - y_margin = (1 + y1[-1] / y_init) / 2 + y_margin = ((1 + y1[-1] / y_init) /2) - margin_text = ( - " " - + str(final_margin) - + "% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc" - ) + margin_text = ' ' + str(final_margin) + '% CapEx margin relative to \n European imports can cover \n local differences in wages, \n taxes, financing, etc' right_bound = 2030.5 right_spline_corr = 0.2 - ax.plot([2030, right_bound], [y_margin, y_margin], "k") - ax.text(right_bound, y_margin, margin_text, verticalalignment="center") - ax.spines["right"].set_position(("data", right_bound - right_spline_corr)) - ax.spines["top"].set_bounds(2022.65, right_bound - right_spline_corr) - ax.spines["bottom"].set_bounds(2022.65, right_bound - right_spline_corr) + ax.plot([2030, right_bound], [y_margin, y_margin], 'k') + ax.text(right_bound, y_margin, margin_text, verticalalignment='center') + ax.spines["right"].set_position(("data", right_bound-right_spline_corr)) + ax.spines["top"].set_bounds(2022.65, right_bound-right_spline_corr) + ax.spines["bottom"].set_bounds(2022.65, right_bound-right_spline_corr) - ax.text(2023, -0.215, "(Fully \nimported)", horizontalalignment="center") - ax.text(2030, -0.215, "(Fully \ndomestic)", horizontalalignment="center") + ax.text(2023, -0.215, '(Fully \nimported)', horizontalalignment='center') + ax.text(2030, -0.215, '(Fully \ndomestic)', horizontalalignment='center') - ax.set_yticklabels([-20, 0, 20, 40, 60, 80, 100]) + ax.set_yticklabels([-20, 0, 20, 40, 60, 80 ,100]) ax.legend(loc=(1, 0.05)) - ax.set_ylabel( - "CapEx breakdown relative to \ncomponents imported from Europe, %" - ) + ax.set_ylabel('CapEx breakdown relative to \ncomponents imported from Europe, %') if fname is not None: myformat(ax) diff --git a/templates/design_module.py b/templates/design_module.py index eed5b2c9..2b1bdafe 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -12,10 +12,12 @@ class TemplateDesign(DesignPhase): expected_config = { "required_input": "unit", - "optional_input": "unit, (optional, default: 'default')", + "optional_input": "unit, (optional, default: 'default')" } - output_config = {"example_output": "unit"} + output_config = { + "example_output": "unit" + } def __init__(self, config, **kwargs): """Creates an instance of `TemplateDesign`.""" @@ -43,7 +45,9 @@ def example_computation(self): def detailed_output(self): """Returns detailed output dictionary.""" - return {"example_detailed_output": self.result} + return { + "example_detailed_output": self.result + } @property def total_cost(self): @@ -56,7 +60,9 @@ def total_cost(self): def design_result(self): """Must match `self.output_config` structure.""" - return {"example_output": self.result} + return { + "example_output": self.result + } # === Annotated Example === @@ -69,21 +75,18 @@ class SparDesign(DesignPhase): # that ProjectManager doesn't raise a warning if doesn't find the input in # a project level config. expected_config = { - "site": { - "depth": "m" - }, # For common inputs that will be shared across many modules, - "plant": { - "num_turbines": "int" - }, # it's best to look up how the variable is named in existing modules - "turbine": { - "turbine_rating": "MW" - }, # so the user doesn't have to input the same thing twice. For example, avoid adding - # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + "site": {"depth": "m"}, # For common inputs that will be shared across many modules, + "plant": {"num_turbines": "int"}, # it's best to look up how the variable is named in existing modules + "turbine": {"turbine_rating": "MW"}, # so the user doesn't have to input the same thing twice. For example, avoid adding + # 'number_turbines' if 'num_turbines' is already used throughout ORBIT + + + # Inputs can be grouped into dictionaries like the following: "spar_design": { - "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates - "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered - "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. + "stiffened_column_CR": "$/t (optional, default: 3120)", # I tend to group module specific cost rates + "tapered_column_CR": "$/t (optional, default: 4220)", # into dictionaries named after the component being considered + "ballast_material_CR": "$/t (optional, default: 100)", # eg. spar_design, gbf_design, etc. "secondary_steel_CR": "$/t (optional, default: 7250)", "towing_speed": "km/h (optional, default: 6)", }, @@ -94,8 +97,8 @@ class SparDesign(DesignPhase): # results are used as inputs to installation modules. As such, these output # names should match the input names of the respective installation module output_config = { - "substructure": { # Typically a design phase ouptuts a component design - "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. + "substructure": { # Typically a design phase ouptuts a component design + "mass": "t", # grouped into a dictionary, eg. "substructure" dict to the left. "ballasted_mass": "t", "unit_cost": "USD", "towing_speed": "km/h", @@ -111,18 +114,13 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library( - config, **kwargs - ) # These first two lines are required in all modules. They initialize the library - self.config = self.validate_config( - config - ) # if it hasn't already been and validate the config against '.expected_config' from above - - self._design = self.config.get( - "spar_design", {} - ) # Not required, but I often save module specific outputs to "_design" for later use - # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library + self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above + + + self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use + # If the "spar_design" sub dictionary isn't found, an empty one is returned to + # work with later methods. self._outputs = {} def run(self): @@ -154,7 +152,7 @@ def stiffened_column_mass(self): rating = self.config["turbine"]["turbine_rating"] depth = self.config["site"]["depth"] - mass = 535.93 + 17.664 * rating**2 + 0.02328 * depth * log(depth) + mass = 535.93 + 17.664 * rating ** 2 + 0.02328 * depth * log(depth) return mass @@ -176,10 +174,8 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get( - "stiffened_column_CR", 3120 - ) # This is how I typically handle outputs. This will look for the key in - # self._design, and return default value if it isn't found. + cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in + # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @property @@ -198,7 +194,7 @@ def ballast_mass(self): """ rating = self.config["turbine"]["turbine_rating"] - mass = -16.536 * rating**2 + 1261.8 * rating - 1554.6 + mass = -16.536 * rating ** 2 + 1261.8 * rating - 1554.6 return mass @@ -223,7 +219,7 @@ def secondary_steel_mass(self): mass = exp( 3.58 - + 0.196 * (rating**0.5) * log(rating) + + 0.196 * (rating ** 0.5) * log(rating) + 0.00001 * depth * log(depth) ) @@ -271,7 +267,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" diff --git a/tests/api/test_wisdem_api.py b/tests/api/test_wisdem_api.py index 4cc5fa25..e15c8156 100644 --- a/tests/api/test_wisdem_api.py +++ b/tests/api/test_wisdem_api.py @@ -11,6 +11,7 @@ def test_wisdem_monopile_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=False, jacket_legs=0) prob.setup() @@ -22,6 +23,7 @@ def test_wisdem_monopile_api_default(): def test_wisdem_jacket_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=False, jacket=True, jacket_legs=3) prob.setup() @@ -33,6 +35,7 @@ def test_wisdem_jacket_api_default(): def test_wisdem_floating_api_default(): + prob = om.Problem(reports=False) prob.model = Orbit(floating=True, jacket=False, jacket_legs=0) prob.setup() diff --git a/tests/conftest.py b/tests/conftest.py index 5579f62c..a480e04e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,7 @@ import pytest from marmot import Environment + from ORBIT.core import Vessel from tests.data import test_weather from ORBIT.core.library import initialize_library, extract_library_specs @@ -23,23 +24,27 @@ def pytest_configure(): @pytest.fixture() def env(): + return Environment("Test Environment", state=test_weather) @pytest.fixture() def wtiv(): + specs = extract_library_specs("wtiv", "test_wtiv") return Vessel("Test WTIV", specs) @pytest.fixture() def feeder(): + specs = extract_library_specs("feeder", "test_feeder") return Vessel("Test Feeder", specs) @pytest.fixture() def cable_vessel(): + specs = extract_library_specs( "array_cable_install_vessel", "test_cable_lay_vessel" ) @@ -48,6 +53,7 @@ def cable_vessel(): @pytest.fixture() def heavy_lift(): + specs = extract_library_specs( "oss_install_vessel", "test_heavy_lift_vessel" ) @@ -56,16 +62,19 @@ def heavy_lift(): @pytest.fixture() def spi_vessel(): + specs = extract_library_specs("spi_vessel", "test_scour_protection_vessel") return Vessel("Test SPI Vessel", specs) @pytest.fixture() def simple_cable(): + return SimpleCable(linear_density=50.0) @pytest.fixture(scope="function") def tmp_yaml_del(): + yield os.remove("tmp.yaml") diff --git a/tests/core/test_environment.py b/tests/core/test_environment.py index b5f5208b..0ce94758 100644 --- a/tests/core/test_environment.py +++ b/tests/core/test_environment.py @@ -8,6 +8,7 @@ import pandas as pd import pytest from marmot import le + from ORBIT.core import Environment from tests.data import test_weather as _weather diff --git a/tests/core/test_library.py b/tests/core/test_library.py index 9cac3f50..7320a9f6 100644 --- a/tests/core/test_library.py +++ b/tests/core/test_library.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT import ProjectManager from ORBIT.core import library from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -57,6 +58,7 @@ def test_extract_library_specs_fail(): def test_phase_specific_file_extraction(): + project = ProjectManager(config) turbine_config = project.create_config_for_phase("TurbineInstallation") monopile_config = project.create_config_for_phase("MonopileInstallation") diff --git a/tests/core/test_port.py b/tests/core/test_port.py index 6415118d..915af401 100644 --- a/tests/core/test_port.py +++ b/tests/core/test_port.py @@ -8,6 +8,7 @@ import pytest from marmot import Environment + from ORBIT.core import Port, Cargo from ORBIT.core.exceptions import ItemNotFound @@ -18,6 +19,7 @@ def __init__(self): def test_port_creation(): + env = Environment() port = Port(env) item = SampleItem() @@ -30,6 +32,7 @@ def test_port_creation(): def test_get_item(): + env = Environment() port = Port(env) item = SampleItem() diff --git a/tests/phases/design/test_array_system_design.py b/tests/phases/design/test_array_system_design.py index 39c42a82..cd1ad5cd 100644 --- a/tests/phases/design/test_array_system_design.py +++ b/tests/phases/design/test_array_system_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ArraySystemDesign, CustomArraySystemDesign from ORBIT.core.exceptions import LibraryItemNotFoundError @@ -208,6 +209,7 @@ def test_correct_turbines(): def test_floating_calculations(): + base = deepcopy(config_full_ring) base["site"]["depth"] = 50 number = base["plant"]["num_turbines"] diff --git a/tests/phases/design/test_cable.py b/tests/phases/design/test_cable.py index ce7a1cd5..e1cf3024 100644 --- a/tests/phases/design/test_cable.py +++ b/tests/phases/design/test_cable.py @@ -11,6 +11,7 @@ import numpy as np import pytest + from ORBIT.phases.design._cables import Cable, Plant cables = { @@ -110,6 +111,7 @@ def test_power_factor(): np.arange(0, 1, 0.15), # inductance range(100, 1001, 150), # capacitance ): + c["conductor_size"] = i[0] c["ac_resistance"] = i[1] c["inductance"] = i[2] diff --git a/tests/phases/design/test_export_system_design.py b/tests/phases/design/test_export_system_design.py index dbe18324..9db78fed 100644 --- a/tests/phases/design/test_export_system_design.py +++ b/tests/phases/design/test_export_system_design.py @@ -8,6 +8,7 @@ from copy import deepcopy import pytest + from ORBIT.core.library import extract_library_specs from ORBIT.phases.design import ExportSystemDesign @@ -103,6 +104,7 @@ def test_design_result(): def test_floating_length_calculations(): + base = deepcopy(config) base["site"]["depth"] = 250 base["export_system_design"]["touchdown_distance"] = 0 diff --git a/tests/phases/design/test_monopile_design.py b/tests/phases/design/test_monopile_design.py index 2f69ed18..0762b46b 100644 --- a/tests/phases/design/test_monopile_design.py +++ b/tests/phases/design/test_monopile_design.py @@ -10,6 +10,7 @@ from itertools import product import pytest + from ORBIT.phases.design import MonopileDesign base = { @@ -36,6 +37,7 @@ product(range(10, 51, 10), range(8, 13, 1), turbines), ) def test_paramater_sweep(depth, mean_ws, turbine): + config = { "site": {"depth": depth, "mean_windspeed": mean_ws}, "plant": {"num_turbines": 20}, @@ -59,6 +61,7 @@ def test_paramater_sweep(depth, mean_ws, turbine): def test_monopile_kwargs(): + test_kwargs = { "yield_stress": 400000000, "load_factor": 1.25, @@ -77,6 +80,7 @@ def test_monopile_kwargs(): base_results = m._outputs["monopile"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v @@ -89,6 +93,7 @@ def test_monopile_kwargs(): def test_transition_piece_kwargs(): + test_kwargs = { # Transition piece specific "monopile_tp_connection_thickness": 0.005, @@ -102,6 +107,7 @@ def test_transition_piece_kwargs(): base_results = m._outputs["transition_piece"] for k, v in test_kwargs.items(): + config = deepcopy(base) config["monopile_design"] = {} config["monopile_design"][k] = v diff --git a/tests/phases/design/test_mooring_system_design.py b/tests/phases/design/test_mooring_system_design.py index c59ef535..88a7a747 100644 --- a/tests/phases/design/test_mooring_system_design.py +++ b/tests/phases/design/test_mooring_system_design.py @@ -9,6 +9,7 @@ from copy import deepcopy import pytest + from ORBIT.phases.design import MooringSystemDesign base = { @@ -20,6 +21,7 @@ @pytest.mark.parametrize("depth", range(10, 1000, 100)) def test_depth_sweep(depth): + config = deepcopy(base) config["site"]["depth"] = depth @@ -32,6 +34,7 @@ def test_depth_sweep(depth): @pytest.mark.parametrize("rating", range(3, 15, 1)) def test_rating_sweeip(rating): + config = deepcopy(base) config["turbine"]["turbine_rating"] = rating @@ -43,6 +46,7 @@ def test_rating_sweeip(rating): def test_drag_embedment_fixed_length(): + m = MooringSystemDesign(base) m.run() @@ -71,6 +75,7 @@ def test_drag_embedment_fixed_length(): def test_custom_num_lines(): + config = deepcopy(base) config["mooring_system_design"] = {"num_lines": 5} diff --git a/tests/phases/design/test_oss_design.py b/tests/phases/design/test_oss_design.py index f17b3bd7..b2dd6316 100644 --- a/tests/phases/design/test_oss_design.py +++ b/tests/phases/design/test_oss_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import OffshoreSubstationDesign base = { @@ -23,6 +24,7 @@ product(range(10, 51, 10), range(3, 13, 1), range(20, 80, 10)), ) def test_parameter_sweep(depth, num_turbines, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": num_turbines}, @@ -49,6 +51,7 @@ def test_parameter_sweep(depth, num_turbines, turbine_rating): def test_oss_kwargs(): + test_kwargs = { "mpt_cost_rate": 13500, "topside_fab_cost_rate": 15500, @@ -69,6 +72,7 @@ def test_oss_kwargs(): base_cost = o.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["substation_design"] = {} config["substation_design"][k] = v diff --git a/tests/phases/design/test_scour_protection_design.py b/tests/phases/design/test_scour_protection_design.py index d4168fd1..301e5894 100644 --- a/tests/phases/design/test_scour_protection_design.py +++ b/tests/phases/design/test_scour_protection_design.py @@ -10,6 +10,7 @@ import numpy as np import pytest + from ORBIT.phases.design import ScourProtectionDesign config_min_defined = { diff --git a/tests/phases/design/test_semisubmersible_design.py b/tests/phases/design/test_semisubmersible_design.py index 30a134f3..7c710fb9 100644 --- a/tests/phases/design/test_semisubmersible_design.py +++ b/tests/phases/design/test_semisubmersible_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SemiSubmersibleDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "truss_CR": 6000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["semisubmersible_design"] = {} config["semisubmersible_design"][k] = v diff --git a/tests/phases/design/test_spar_design.py b/tests/phases/design/test_spar_design.py index dbc937c1..393cf7c1 100644 --- a/tests/phases/design/test_spar_design.py +++ b/tests/phases/design/test_spar_design.py @@ -8,6 +8,7 @@ from itertools import product import pytest + from ORBIT.phases.design import SparDesign base = { @@ -22,6 +23,7 @@ "depth,turbine_rating", product(range(100, 1201, 200), range(3, 15, 1)) ) def test_parameter_sweep(depth, turbine_rating): + config = { "site": {"depth": depth}, "plant": {"num_turbines": 50}, @@ -39,6 +41,7 @@ def test_parameter_sweep(depth, turbine_rating): def test_design_kwargs(): + test_kwargs = { "stiffened_column_CR": 3000, "tapered_column_CR": 4000, @@ -51,6 +54,7 @@ def test_design_kwargs(): base_cost = s.total_cost for k, v in test_kwargs.items(): + config = deepcopy(base) config["spar_design"] = {} config["spar_design"][k] = v diff --git a/tests/phases/install/cable_install/test_array_install.py b/tests/phases/install/cable_install/test_array_install.py index f9b1c9a9..5a01c14b 100644 --- a/tests/phases/install/cable_install/test_array_install.py +++ b/tests/phases/install/cable_install/test_array_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ArrayCableInstallation(config) assert sim.env @@ -35,6 +37,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ArrayCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -50,6 +53,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ArrayCableInstallation(config, weather=weather) sim.run() @@ -68,6 +72,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ArrayCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -84,6 +89,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ArrayCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -108,6 +114,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_array_install(): + sim = ArrayCableInstallation(base_config) sim.run() baseline = sim.total_phase_time @@ -124,6 +131,7 @@ def test_kwargs_for_array_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -155,6 +163,7 @@ def test_kwargs_for_array_install(): def test_kwargs_for_array_install_in_ProjectManager(): + base = deepcopy(base_config) base["install_phases"] = ["ArrayCableInstallation"] @@ -174,6 +183,7 @@ def test_kwargs_for_array_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/cable_install/test_cable_tasks.py b/tests/phases/install/cable_install/test_cable_tasks.py index f3d03350..3ab42d15 100644 --- a/tests/phases/install/cable_install/test_cable_tasks.py +++ b/tests/phases/install/cable_install/test_cable_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.cable_install.common import ( tow_plow, @@ -27,6 +28,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) @@ -57,6 +59,7 @@ def test_load_cable_on_vessel(env, cable_vessel, feeder, simple_cable): ], ) def test_task(env, cable_vessel, task, log, args): + env.register(cable_vessel) cable_vessel.initialize(mobilize=False) diff --git a/tests/phases/install/cable_install/test_export_install.py b/tests/phases/install/cable_install/test_export_install.py index e837176c..34669075 100644 --- a/tests/phases/install/cable_install/test_export_install.py +++ b/tests/phases/install/cable_install/test_export_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -27,6 +28,7 @@ "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_simulation_setup(config): + sim = ExportCableInstallation(config) assert sim.env assert sim.cable @@ -40,6 +42,7 @@ def test_simulation_setup(config): "config", (base_config, simul_config), ids=["separate", "simultaneous"] ) def test_vessel_initialization(config): + sim = ExportCableInstallation(config) assert sim.install_vessel assert sim.install_vessel.cable_storage @@ -55,6 +58,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(config, weather): + sim = ExportCableInstallation(config, weather=weather) sim.run() @@ -73,6 +77,7 @@ def test_for_complete_logging(config, weather): def test_simultaneous_speed_kwargs(): + sim = ExportCableInstallation(simul_config) sim.run() baseline = sim.total_phase_time @@ -89,6 +94,7 @@ def test_simultaneous_speed_kwargs(): def test_separate_speed_kwargs(): + sim = ExportCableInstallation(base_config) sim.run() df = pd.DataFrame(sim.env.actions) @@ -113,6 +119,7 @@ def test_separate_speed_kwargs(): def test_kwargs_for_export_install(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1} } @@ -143,6 +150,7 @@ def test_kwargs_for_export_install(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: @@ -174,6 +182,7 @@ def test_kwargs_for_export_install(): def test_kwargs_for_export_install_in_ProjectManager(): + new_export_system = { "cable": {"linear_density": 50.0, "sections": [1000], "number": 1}, "system_cost": 200e6, @@ -205,6 +214,7 @@ def test_kwargs_for_export_install_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if "speed" in kw: diff --git a/tests/phases/install/jacket_install/test_jacket_install.py b/tests/phases/install/jacket_install/test_jacket_install.py index c601a5c6..6811e631 100644 --- a/tests/phases/install/jacket_install/test_jacket_install.py +++ b/tests/phases/install/jacket_install/test_jacket_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = JacketInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = JacketInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = JacketInstallation(config, weather=weather) sim.run() @@ -93,6 +97,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_num_legs(config): + base = JacketInstallation(config) base.run() @@ -111,6 +116,7 @@ def test_num_legs(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_foundation_type(config): + base = JacketInstallation(config) base.run() @@ -128,6 +134,7 @@ def test_foundation_type(config): def test_kwargs_piles(): + sim = JacketInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -147,6 +154,7 @@ def test_kwargs_piles(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -168,6 +176,7 @@ def test_kwargs_piles(): def test_kwargs_suction(): + config_wtiv_suction = deepcopy(config_wtiv) config_wtiv_suction["jacket"]["foundation_type"] = "suction" @@ -188,6 +197,7 @@ def test_kwargs_suction(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} diff --git a/tests/phases/install/monopile_install/test_monopile_install.py b/tests/phases/install/monopile_install/test_monopile_install.py index 1759bc3e..57538063 100644 --- a/tests/phases/install/monopile_install/test_monopile_install.py +++ b/tests/phases/install/monopile_install/test_monopile_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -28,6 +29,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = MonopileInstallation(config) assert sim.config == config assert sim.env @@ -48,6 +50,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = MonopileInstallation(config) assert sim.wtiv assert sim.wtiv.jacksys @@ -71,6 +74,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = MonopileInstallation(config, weather=weather) sim.run() @@ -88,6 +92,7 @@ def test_for_complete_logging(weather, config): def test_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -108,6 +113,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -139,6 +145,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["MonopileInstallation"] project = ProjectManager(base) @@ -161,6 +168,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -195,6 +203,7 @@ def test_kwargs_in_ProjectManager(): def test_grout_kwargs(): + sim = MonopileInstallation(config_wtiv) sim.run() diff --git a/tests/phases/install/monopile_install/test_monopile_tasks.py b/tests/phases/install/monopile_install/test_monopile_tasks.py index 2fa11d9e..bff023f5 100644 --- a/tests/phases/install/monopile_install/test_monopile_tasks.py +++ b/tests/phases/install/monopile_install/test_monopile_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.monopile_install.common import ( drive_monopile, @@ -34,6 +35,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -53,6 +55,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/mooring_install/test_mooring_install.py b/tests/phases/install/mooring_install/test_mooring_install.py index 3583bbda..116f7558 100644 --- a/tests/phases/install/mooring_install/test_mooring_install.py +++ b/tests/phases/install/mooring_install/test_mooring_install.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -60,6 +61,7 @@ def test_full_run_logging(weather): ], ) def test_kwargs(anchor, key): + new = deepcopy(config) new["mooring_system"]["anchor_type"] = anchor @@ -72,6 +74,7 @@ def test_kwargs(anchor, key): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -100,6 +103,7 @@ def test_kwargs(anchor, key): ], ) def test_kwargs_in_ProjectManager(anchor, key): + base = deepcopy(config) base["mooring_system"]["anchor_type"] = anchor base["install_phases"] = ["MooringSystemInstallation"] @@ -113,6 +117,7 @@ def test_kwargs_in_ProjectManager(anchor, key): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} new_config = deepcopy(base) diff --git a/tests/phases/install/oss_install/test_oss_install.py b/tests/phases/install/oss_install/test_oss_install.py index 30ed4475..be32be3d 100644 --- a/tests/phases/install/oss_install/test_oss_install.py +++ b/tests/phases/install/oss_install/test_oss_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["single_feeder", "multi_feeder"], ) def test_simulation_setup(config): + sim = OffshoreSubstationInstallation(config) assert sim.config == config assert sim.env @@ -43,6 +45,7 @@ def test_simulation_setup(config): def test_floating_simulation_setup(): + sim = FloatingSubstationInstallation(config_floating) assert sim.config == config_floating assert sim.env @@ -55,6 +58,7 @@ def test_floating_simulation_setup(): ids=["single_feeder", "multi_feeder"], ) def test_vessel_initialization(config): + sim = OffshoreSubstationInstallation(config) assert sim.oss_vessel assert sim.oss_vessel.crane @@ -78,6 +82,7 @@ def test_vessel_initialization(config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + # No weather sim = OffshoreSubstationInstallation(config, weather=weather) sim.run() @@ -99,6 +104,7 @@ def test_for_complete_logging(weather, config): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging_floating(weather): + sim = FloatingSubstationInstallation(config_floating, weather=weather) sim.run() @@ -112,6 +118,7 @@ def test_for_complete_logging_floating(weather): def test_kwargs(): + sim = OffshoreSubstationInstallation(config_single) sim.run() baseline = sim.total_phase_time @@ -132,6 +139,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": @@ -163,6 +171,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_single) base["install_phases"] = ["OffshoreSubstationInstallation"] @@ -186,6 +195,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] if kw == "mono_drive_rate": diff --git a/tests/phases/install/oss_install/test_oss_tasks.py b/tests/phases/install/oss_install/test_oss_tasks.py index 758df489..67a28c40 100644 --- a/tests/phases/install/oss_install/test_oss_tasks.py +++ b/tests/phases/install/oss_install/test_oss_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.oss_install.common import ( lift_topside, @@ -24,6 +25,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -42,6 +44,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/install/quayside_assembly_tow/test_common.py b/tests/phases/install/quayside_assembly_tow/test_common.py index b9a08bac..00fa2b4e 100644 --- a/tests/phases/install/quayside_assembly_tow/test_common.py +++ b/tests/phases/install/quayside_assembly_tow/test_common.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from ORBIT.core import WetStorage from ORBIT.phases.install.quayside_assembly_tow.common import ( TurbineAssemblyLine, @@ -27,6 +28,7 @@ ], ) def test_SubstructureAssemblyLine(env, num, assigned, expected): + _assigned = len(assigned) storage = WetStorage(env, capacity=float("inf")) @@ -52,6 +54,7 @@ def test_SubstructureAssemblyLine(env, num, assigned, expected): ], ) def test_TurbineAssemblyLine(env, num, assigned): + _assigned = len(assigned) feed = WetStorage(env, capacity=float("inf")) target = WetStorage(env, capacity=float("inf")) @@ -89,6 +92,7 @@ def test_TurbineAssemblyLine(env, num, assigned): ], ) def test_Sub_to_Turbine_assembly_interaction(env, sub_lines, turb_lines): + num_turbines = 50 assigned = [1] * num_turbines diff --git a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py index 25d7db92..dafad84b 100644 --- a/tests/phases/install/quayside_assembly_tow/test_gravity_based.py +++ b/tests/phases/install/quayside_assembly_tow/test_gravity_based.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import GravityBasedInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = GravityBasedInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = GravityBasedInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/quayside_assembly_tow/test_moored.py b/tests/phases/install/quayside_assembly_tow/test_moored.py index 72619642..e1fc0af7 100644 --- a/tests/phases/install/quayside_assembly_tow/test_moored.py +++ b/tests/phases/install/quayside_assembly_tow/test_moored.py @@ -8,6 +8,7 @@ import pandas as pd import pytest + from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import MooredSubInstallation @@ -17,6 +18,7 @@ def test_simulation_setup(): + sim = MooredSubInstallation(config) assert sim.config == config assert sim.env @@ -39,6 +41,7 @@ def test_simulation_setup(): ) @pytest.mark.parametrize("config", (config, no_supply)) def test_for_complete_logging(weather, config): + sim = MooredSubInstallation(config, weather=weather) sim.run() diff --git a/tests/phases/install/scour_protection_install/test_scour_protection.py b/tests/phases/install/scour_protection_install/test_scour_protection.py index ae1c9313..85e372c7 100644 --- a/tests/phases/install/scour_protection_install/test_scour_protection.py +++ b/tests/phases/install/scour_protection_install/test_scour_protection.py @@ -12,6 +12,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -50,6 +51,7 @@ def test_full_run_logging(weather): def test_kwargs(): + sim = ScourProtectionInstallation(config) sim.run() baseline = sim.total_phase_time @@ -59,6 +61,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -80,6 +83,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config) base["install_phases"] = ["ScourProtectionInstallation"] @@ -92,6 +96,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} diff --git a/tests/phases/install/test_install_phase.py b/tests/phases/install/test_install_phase.py index cba9802c..6b600eb2 100644 --- a/tests/phases/install/test_install_phase.py +++ b/tests/phases/install/test_install_phase.py @@ -9,6 +9,7 @@ import pandas as pd import pytest from marmot import Environment + from ORBIT.phases.install import InstallPhase @@ -44,6 +45,7 @@ def setup_simulation(self): def test_abstract_methods(): + with pytest.raises(TypeError): install = BadInstallPhase(base_config) @@ -51,6 +53,7 @@ def test_abstract_methods(): def test_run(): + sim = SampleInstallPhase(base_config) sim.run(until=10) diff --git a/tests/phases/install/turbine_install/test_turbine_install.py b/tests/phases/install/turbine_install/test_turbine_install.py index 0592999a..aac2de9f 100644 --- a/tests/phases/install/turbine_install/test_turbine_install.py +++ b/tests/phases/install/turbine_install/test_turbine_install.py @@ -10,6 +10,7 @@ import pandas as pd import pytest + from ORBIT import ProjectManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs @@ -32,6 +33,7 @@ ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_simulation_setup(config): + sim = TurbineInstallation(config) assert sim.config == config assert sim.env @@ -54,6 +56,7 @@ def test_simulation_setup(config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_vessel_creation(config): + sim = TurbineInstallation(config) assert sim.wtiv assert sim.wtiv.crane @@ -77,6 +80,7 @@ def test_vessel_creation(config): "config, expected", [(config_wtiv, 72), (config_long_mobilize, 14 * 24)] ) def test_vessel_mobilize(config, expected): + sim = TurbineInstallation(config) assert sim.wtiv @@ -93,6 +97,7 @@ def test_vessel_mobilize(config, expected): "weather", (None, test_weather), ids=["no_weather", "test_weather"] ) def test_for_complete_logging(weather, config): + sim = TurbineInstallation(config, weather=weather) sim.run() @@ -115,6 +120,7 @@ def test_for_complete_logging(weather, config): ids=["wtiv_only", "single_feeder", "multi_feeder", "floating"], ) def test_for_complete_installation(config): + sim = TurbineInstallation(config) sim.run() @@ -125,6 +131,7 @@ def test_for_complete_installation(config): def test_kwargs(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = sim.total_phase_time @@ -146,6 +153,7 @@ def test_kwargs(): failed = [] for kw in keywords: + default = pt[kw] kwargs = {kw: default + 2} @@ -167,6 +175,7 @@ def test_kwargs(): def test_kwargs_in_ProjectManager(): + base = deepcopy(config_wtiv) base["install_phases"] = ["TurbineInstallation"] @@ -191,6 +200,7 @@ def test_kwargs_in_ProjectManager(): failed = [] for kw in keywords: + default = pt[kw] processes = {kw: default + 2} @@ -215,6 +225,7 @@ def test_kwargs_in_ProjectManager(): def test_multiple_tower_sections(): + sim = TurbineInstallation(config_wtiv) sim.run() baseline = len( @@ -234,6 +245,7 @@ def test_multiple_tower_sections(): df = pd.DataFrame(sim.env.actions) for vessel in df["agent"].unique(): + vl = df[df["agent"] == vessel].copy() vl = vl.assign(shift=(vl["time"] - vl["time"].shift(1))) diff --git a/tests/phases/install/turbine_install/test_turbine_tasks.py b/tests/phases/install/turbine_install/test_turbine_tasks.py index 2042f639..055da73d 100644 --- a/tests/phases/install/turbine_install/test_turbine_tasks.py +++ b/tests/phases/install/turbine_install/test_turbine_tasks.py @@ -9,6 +9,7 @@ import pytest + from ORBIT.core.exceptions import MissingComponent from ORBIT.phases.install.turbine_install.common import ( lift_nacelle, @@ -32,6 +33,7 @@ ], ) def test_task(env, wtiv, task, log, args): + env.register(wtiv) wtiv.initialize(mobilize=False) @@ -54,6 +56,7 @@ def test_task(env, wtiv, task, log, args): ], ) def test_task_fails(env, feeder, task, log, args): + env.register(feeder) feeder.initialize(mobilize=False) diff --git a/tests/phases/test_base.py b/tests/phases/test_base.py index 01e37b7b..209983ac 100644 --- a/tests/phases/test_base.py +++ b/tests/phases/test_base.py @@ -18,12 +18,14 @@ def test_good_config(): + config = deepcopy(expected_config) missing = BasePhase._check_keys(expected_config, config) assert len(missing) == 0 def test_missing_key(): + config = deepcopy(expected_config) _ = config.pop("param1") missing = BasePhase._check_keys(expected_config, config) @@ -31,6 +33,7 @@ def test_missing_key(): def test_optional(): + config = deepcopy(expected_config) _ = config["param2"].pop("param4") missing = BasePhase._check_keys(expected_config, config) @@ -38,6 +41,7 @@ def test_optional(): def test_variable_key(): + config = deepcopy(expected_config) _ = config.pop("param5 (variable)") @@ -46,6 +50,7 @@ def test_variable_key(): def test_optional_dict(): + config = deepcopy(expected_config) _ = config.pop("param6") diff --git a/tests/test_config_management.py b/tests/test_config_management.py index ffd84920..f635f271 100644 --- a/tests/test_config_management.py +++ b/tests/test_config_management.py @@ -7,6 +7,7 @@ import os import pytest + from ORBIT import ProjectManager, load_config, save_config from ORBIT.core.library import extract_library_specs @@ -14,6 +15,7 @@ def test_save_and_load_equality(tmp_yaml_del): + save_config(complete_project, "tmp.yaml", overwrite=True) new = load_config("tmp.yaml") @@ -21,6 +23,7 @@ def test_save_and_load_equality(tmp_yaml_del): def test_orbit_version_ProjectManager(): + config = ProjectManager.compile_input_dict( ["MonopileDesign", "MonopileInstallation"] ) diff --git a/tests/test_design_install_phase_interactions.py b/tests/test_design_install_phase_interactions.py index 656db0d8..059202fb 100644 --- a/tests/test_design_install_phase_interactions.py +++ b/tests/test_design_install_phase_interactions.py @@ -6,8 +6,9 @@ from copy import deepcopy -from ORBIT import ProjectManager from numpy.testing import assert_almost_equal + +from ORBIT import ProjectManager from ORBIT.core.library import extract_library_specs fixed = extract_library_specs("config", "complete_project") @@ -15,6 +16,7 @@ def test_fixed_phase_cost_passing(): + project = ProjectManager(fixed) project.run() @@ -45,6 +47,7 @@ def test_fixed_phase_cost_passing(): def test_floating_phase_cost_passing(): + project = ProjectManager(floating) project.run() diff --git a/tests/test_parametric.py b/tests/test_parametric.py index 5d33cfca..4d73da75 100644 --- a/tests/test_parametric.py +++ b/tests/test_parametric.py @@ -7,8 +7,9 @@ import pandas as pd import pytest -from ORBIT import ProjectManager, ParametricManager from benedict import benedict + +from ORBIT import ProjectManager, ParametricManager from tests.data import test_weather from ORBIT.core.library import extract_library_specs from ORBIT.phases.install import TurbineInstallation @@ -23,6 +24,7 @@ def test_for_equal_results(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 project = ProjectManager(config) @@ -35,6 +37,7 @@ def test_for_equal_results(): def test_weather(): + without = ParametricManager(complete_project, params, funcs) without.run() @@ -47,6 +50,7 @@ def test_weather(): def test_individual_phase(): + config = benedict(deepcopy(complete_project)) config["site.distance"] = 20 phase = TurbineInstallation(config) @@ -63,6 +67,7 @@ def test_individual_phase(): def test_bad_result_attribute(): + funcs = {"result": lambda phase: phase.nonexistent_result} parametric = ParametricManager( @@ -74,6 +79,7 @@ def test_bad_result_attribute(): def test_bad_result_structure(): + funcs = {"result": "bos_capex"} parametric = ParametricManager( @@ -85,6 +91,7 @@ def test_bad_result_structure(): def test_product_option(): + params = {"site.distance": [20, 40, 60], "site.depth": [20, 40, 60]} parametric = ParametricManager( diff --git a/tests/test_project_manager.py b/tests/test_project_manager.py index 9cbf9ad3..7e62a225 100644 --- a/tests/test_project_manager.py +++ b/tests/test_project_manager.py @@ -8,9 +8,10 @@ import pandas as pd import pytest + from ORBIT import ProjectManager +from ORBIT.phases import InstallPhase, DesignPhase from tests.data import test_weather -from ORBIT.phases import DesignPhase, InstallPhase from ORBIT.manager import ProjectProgress from ORBIT.core.library import extract_library_specs from ORBIT.core.exceptions import ( @@ -25,10 +26,10 @@ config = extract_library_specs("config", "project_manager") complete_project = extract_library_specs("config", "complete_project") - ### Top Level @pytest.mark.parametrize("weather", (None, weather_df)) def test_complete_run(weather): + project = ProjectManager(config, weather=weather) project.run() @@ -46,9 +47,11 @@ def test_for_required_phase_structure(): """ for p in ProjectManager._install_phases: + assert isinstance(p.expected_config, dict) for p in ProjectManager._design_phases: + assert isinstance(p.expected_config, dict) assert isinstance(p.output_config, dict) @@ -127,6 +130,7 @@ class SpecificTurbineInstallation(InstallPhase): ] for test in tests: + i, expected = test response = TestProjectManager.find_key_match(i) @@ -139,11 +143,13 @@ class SpecificTurbineInstallation(InstallPhase): ] for f in fails: + assert TestProjectManager.find_key_match(f) is None ### Overlapping Install Phases def test_install_phase_start_parsing(): + config_mixed_starts = deepcopy(config) config_mixed_starts["install_phases"] = { "MonopileInstallation": 0, @@ -163,6 +169,7 @@ def test_install_phase_start_parsing(): def test_chained_dependencies(): + config_chained = deepcopy(config) config_chained["spi_vessel"] = "test_scour_protection_vessel" config_chained["scour_protection"] = { @@ -226,6 +233,7 @@ def test_index_starts(m_start, t_start): ], ) def test_start_dates_with_weather(m_start, t_start, expected): + config_with_defined_starts = deepcopy(config) config_with_defined_starts["install_phases"] = { "MonopileInstallation": m_start, @@ -275,6 +283,7 @@ def test_duplicate_phase_definitions(): def test_custom_install_phases(): + # Not a subclass class CustomInstallPhase: pass @@ -296,6 +305,7 @@ class MonopileInstallation(InstallPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileInstallation) + # Bad name format class MonopileInstallation_Custom(InstallPhase): pass @@ -308,13 +318,11 @@ class CustomInstallPhase(InstallPhase): pass ProjectManager.register_install_phase(CustomInstallPhase) - assert ( - ProjectManager.find_key_match("CustomInstallPhase") - == CustomInstallPhase - ) + assert ProjectManager.find_key_match("CustomInstallPhase") == CustomInstallPhase def test_custom_design_phases(): + # Not a subclass class CustomDesignPhase: pass @@ -336,6 +344,7 @@ class MonopileDesign(DesignPhase): with pytest.raises(ValueError): ProjectManager.register_install_phase(MonopileDesign) + # Bad name format class MonopileDesign_Custom(DesignPhase): pass @@ -348,13 +357,11 @@ class CustomDesignPhase(DesignPhase): pass ProjectManager.register_design_phase(CustomDesignPhase) - assert ( - ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase - ) - + assert ProjectManager.find_key_match("CustomDesignPhase") == CustomDesignPhase ### Design Phase Interactions def test_design_phases(): + config_with_design = deepcopy(config) # Add MonopileDesign @@ -379,6 +386,7 @@ def test_design_phases(): ### Outputs def test_resolve_project_capacity(): + # Missing turbine rating config1 = {"plant": {"capacity": 600, "num_turbines": 40}} @@ -459,6 +467,7 @@ def test_resolve_project_capacity(): ### Exceptions def test_incomplete_config(): + incomplete_config = deepcopy(config) _ = incomplete_config["site"].pop("depth") @@ -468,6 +477,7 @@ def test_incomplete_config(): def test_wrong_phases(): + wrong_phases = deepcopy(config) wrong_phases["install_phases"].append("IncorrectPhaseName") @@ -477,6 +487,7 @@ def test_wrong_phases(): def test_bad_dates(): + bad_dates = deepcopy(config) bad_dates["install_phases"] = { "MonopileInstallation": "03/01/2015", @@ -489,6 +500,7 @@ def test_bad_dates(): def test_no_defined_start(): + missing_start = deepcopy(config) missing_start["install_phases"] = { "MonopileInstallation": ("TurbineInstallation", 0.1), @@ -501,6 +513,7 @@ def test_no_defined_start(): def test_circular_dependencies(): + circular_deps = deepcopy(config) circular_deps["spi_vessel"] = "test_scour_protection_vessel" circular_deps["scour_protection"] = { @@ -519,6 +532,7 @@ def test_circular_dependencies(): def test_dependent_phase_ordering(): + wrong_order = deepcopy(config) wrong_order["spi_vessel"] = "test_scour_protection_vessel" wrong_order["scour_protection"] = { @@ -538,6 +552,7 @@ def test_dependent_phase_ordering(): def test_ProjectProgress(): + data = [ ("Export System", 10), ("Offshore Substation", 20), @@ -577,6 +592,7 @@ def test_ProjectProgress(): def test_ProjectProgress_with_incomplete_project(): + project = ProjectManager(config) project.run() @@ -591,6 +607,7 @@ def test_ProjectProgress_with_incomplete_project(): def test_ProjectProgress_with_complete_project(): + project = ProjectManager(complete_project) project.run() @@ -616,6 +633,7 @@ def test_ProjectProgress_with_complete_project(): def test_monthly_expenses(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_expenses @@ -631,6 +649,7 @@ def test_monthly_expenses(): def test_monthly_revenue(): + project = ProjectManager(complete_project) project.run() _ = project.monthly_revenue @@ -647,6 +666,7 @@ def test_monthly_revenue(): def test_cash_flow(): + project = ProjectManager(complete_project) project.run() _ = project.cash_flow @@ -664,6 +684,7 @@ def test_cash_flow(): def test_npv(): + project = ProjectManager(complete_project) project.run() baseline = project.npv @@ -700,6 +721,7 @@ def test_npv(): def test_soft_costs(): + project = ProjectManager(complete_project) baseline = project.soft_capex @@ -735,6 +757,7 @@ def test_soft_costs(): def test_project_costs(): + project = ProjectManager(complete_project) baseline = project.project_capex @@ -760,6 +783,7 @@ def test_project_costs(): def test_capex_categories(): + project = ProjectManager(complete_project) project.run() baseline = project.capex_breakdown diff --git a/versioneer.py b/versioneer.py index 96361d2f..64fea1c8 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,3 +1,4 @@ + # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. @@ -276,18 +277,16 @@ """ from __future__ import print_function - -import os -import re -import sys -import json -import errno -import subprocess - try: import configparser except ImportError: import ConfigParser as configparser +import errno +import json +import os +import re +import subprocess +import sys class VersioneerConfig: @@ -309,13 +308,11 @@ def get_root(): setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ( - "Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND')." - ) + err = ("Versioneer was unable to run the project root directory. " + "Versioneer requires setup.py to be executed from " + "its immediate directory (like 'python setup.py COMMAND'), " + "or in a way that lets it use sys.argv[0] to find the root " + "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools @@ -328,10 +325,8 @@ def get_root(): me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: - print( - "Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py) - ) + print("Warning: build in %s is using versioneer.py from %s" + % (os.path.dirname(me), versioneer_py)) except NameError: pass return root @@ -353,7 +348,6 @@ def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None - cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" @@ -378,20 +372,17 @@ class NotThisMethod(Exception): def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f - return decorate -def run_command( - commands, args, cwd=None, verbose=False, hide_stderr=False, env=None -): +def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, + env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None @@ -399,13 +390,10 @@ def run_command( try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen( - [c] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - ) + p = subprocess.Popen([c] + args, cwd=cwd, env=env, + stdout=subprocess.PIPE, + stderr=(subprocess.PIPE if hide_stderr + else None)) break except EnvironmentError: e = sys.exc_info()[1] @@ -430,9 +418,7 @@ def run_command( return stdout, p.returncode -LONG_VERSION_PY[ - "git" -] = ''' +LONG_VERSION_PY['git'] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build @@ -1007,7 +993,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " - tags = set([r[len(TAG) :] for r in refs if r.startswith(TAG)]) + tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d @@ -1016,7 +1002,7 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r"\d", r)]) + tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: @@ -1024,26 +1010,19 @@ def git_versions_from_keywords(keywords, tag_prefix, verbose): for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] + r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } + return {"version": r, + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": None, + "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } + return {"version": "0+unknown", + "full-revisionid": keywords["full"].strip(), + "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") @@ -1058,9 +1037,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] - out, rc = run_command( - GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True - ) + out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, + hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) @@ -1068,19 +1046,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command( - GITS, - [ - "describe", - "--tags", - "--dirty", - "--always", - "--long", - "--match", - "%s*" % tag_prefix, - ], - cwd=root, - ) + describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", + "--always", "--long", + "--match", "%s*" % tag_prefix], + cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") @@ -1103,18 +1072,17 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] + git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) + mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ( - "unable to parse git-describe output: '%s'" % describe_out - ) + pieces["error"] = ("unable to parse git-describe output: '%s'" + % describe_out) return pieces # tag @@ -1123,12 +1091,10 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) + pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" + % (full_tag, tag_prefix)) return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] + pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) @@ -1139,15 +1105,13 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): else: # HEX: no tags pieces["closest-tag"] = None - count_out, rc = run_command( - GITS, ["rev-list", "HEAD", "--count"], cwd=root - ) + count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], + cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[ - 0 - ].strip() + date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], + cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces @@ -1203,22 +1167,16 @@ def versions_from_parentdir(parentdir_prefix, root, verbose): for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } + return {"version": dirname[len(parentdir_prefix):], + "full-revisionid": None, + "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) + print("Tried directories %s but none started with prefix %s" % + (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @@ -1247,17 +1205,11 @@ def versions_from_file(filename): contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") - mo = re.search( - r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: - mo = re.search( - r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, - re.M | re.S, - ) + mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", + contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) @@ -1266,9 +1218,8 @@ def versions_from_file(filename): def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) - contents = json.dumps( - versions, sort_keys=True, indent=1, separators=(",", ": ") - ) + contents = json.dumps(versions, sort_keys=True, + indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) @@ -1300,7 +1251,8 @@ def render_pep440(pieces): rendered += ".dirty" else: # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) + rendered = "0+untagged.%d.g%s" % (pieces["distance"], + pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered @@ -1414,13 +1366,11 @@ def render_git_describe_long(pieces): def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } + return {"version": "unknown", + "full-revisionid": pieces.get("long"), + "dirty": None, + "error": pieces["error"], + "date": None} if not style or style == "default": style = "pep440" # the default @@ -1440,13 +1390,9 @@ def render(pieces, style): else: raise ValueError("unknown style '%s'" % style) - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } + return {"version": rendered, "full-revisionid": pieces["long"], + "dirty": pieces["dirty"], "error": None, + "date": pieces.get("date")} class VersioneerBadRootError(Exception): @@ -1469,9 +1415,8 @@ def get_versions(verbose=False): handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose - assert ( - cfg.versionfile_source is not None - ), "please set versioneer.versionfile_source" + assert cfg.versionfile_source is not None, \ + "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) @@ -1525,13 +1470,9 @@ def get_versions(verbose=False): if verbose: print("unable to compute version") - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } + return {"version": "0+unknown", "full-revisionid": None, + "dirty": None, "error": "unable to compute version", + "date": None} def get_version(): @@ -1580,7 +1521,6 @@ def run(self): print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools @@ -1613,17 +1553,14 @@ def run(self): # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: - target_versionfile = os.path.join( - self.build_lib, cfg.versionfile_build - ) + target_versionfile = os.path.join(self.build_lib, + cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) - cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ @@ -1644,21 +1581,17 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] - if "py2exe" in sys.modules: # py2exe enabled? + if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: @@ -1677,17 +1610,13 @@ def run(self): os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - + f.write(LONG % + {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments @@ -1714,10 +1643,8 @@ def make_release_tree(self, base_dir, files): # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) - write_to_version_file( - target_versionfile, self._versioneer_generated_versions - ) - + write_to_version_file(target_versionfile, + self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds @@ -1772,15 +1699,11 @@ def do_setup(): root = get_root() try: cfg = get_config_from_root(root) - except ( - EnvironmentError, - configparser.NoSectionError, - configparser.NoOptionError, - ) as e: + except (EnvironmentError, configparser.NoSectionError, + configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print( - "Adding sample versioneer config to setup.cfg", file=sys.stderr - ) + print("Adding sample versioneer config to setup.cfg", + file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) @@ -1789,18 +1712,15 @@ def do_setup(): print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") + f.write(LONG % {"DOLLAR": "$", + "STYLE": cfg.style, + "TAG_PREFIX": cfg.tag_prefix, + "PARENTDIR_PREFIX": cfg.parentdir_prefix, + "VERSIONFILE_SOURCE": cfg.versionfile_source, + }) + + ipy = os.path.join(os.path.dirname(cfg.versionfile_source), + "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: @@ -1842,10 +1762,8 @@ def do_setup(): else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: - print( - " appending versionfile_source ('%s') to MANIFEST.in" - % cfg.versionfile_source - ) + print(" appending versionfile_source ('%s') to MANIFEST.in" % + cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: From ba2349610261741832359099d29df45e3cf48777 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 1 Mar 2023 21:00:13 +0000 Subject: [PATCH 17/19] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- LICENSE | 2 +- ORBIT/core/cargo.py | 2 +- ORBIT/phases/install/oss_install/floating.py | 2 +- docs/Makefile | 2 +- library/turbines/15MW_generic.yaml | 2 +- templates/design_module.py | 10 +++++----- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/LICENSE b/LICENSE index dbb692d8..1c0c15ea 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2020 Alliance for Sustainable Energy, LLC + Copyright (c) 2020 Alliance for Sustainable Energy, LLC Apache License Version 2.0, January 2004 diff --git a/ORBIT/core/cargo.py b/ORBIT/core/cargo.py index d02ab03f..843d655e 100644 --- a/ORBIT/core/cargo.py +++ b/ORBIT/core/cargo.py @@ -6,7 +6,7 @@ class Cargo(Object): - + def __repr__(self): return self.type diff --git a/ORBIT/phases/install/oss_install/floating.py b/ORBIT/phases/install/oss_install/floating.py index 6580e19a..c2d1ca2b 100644 --- a/ORBIT/phases/install/oss_install/floating.py +++ b/ORBIT/phases/install/oss_install/floating.py @@ -144,7 +144,7 @@ def initialize_installation_vessel(self): @property def detailed_output(self): - + return {} diff --git a/docs/Makefile b/docs/Makefile index 298ea9e2..51285967 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -16,4 +16,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/library/turbines/15MW_generic.yaml b/library/turbines/15MW_generic.yaml index 50478a79..0a3683f9 100644 --- a/library/turbines/15MW_generic.yaml +++ b/library/turbines/15MW_generic.yaml @@ -17,4 +17,4 @@ tower: type: Tower length: 150 mass: 480 # t -turbine_rating: 15 # MW \ No newline at end of file +turbine_rating: 15 # MW diff --git a/templates/design_module.py b/templates/design_module.py index 2b1bdafe..b308113b 100644 --- a/templates/design_module.py +++ b/templates/design_module.py @@ -114,13 +114,13 @@ def __init__(self, config, **kwargs): config : dict """ - config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library + config = self.initialize_library(config, **kwargs) # These first two lines are required in all modules. They initialize the library self.config = self.validate_config(config) # if it hasn't already been and validate the config against '.expected_config' from above - + self._design = self.config.get("spar_design", {}) # Not required, but I often save module specific outputs to "_design" for later use # If the "spar_design" sub dictionary isn't found, an empty one is returned to - # work with later methods. + # work with later methods. self._outputs = {} def run(self): @@ -174,7 +174,7 @@ def stiffened_column_cost(self): Calculates the cost of the stiffened column for a single spar. From original OffshoreBOS model. """ - cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in + cr = self._design.get("stiffened_column_CR", 3120) # This is how I typically handle outputs. This will look for the key in # self._design, and return default value if it isn't found. return self.stiffened_column_mass * cr @@ -267,7 +267,7 @@ def substructure_cost(self): # The following properties are required methods for a DesignPhase # .detailed_output returns any relevant detailed outputs from the module - # in a dictionary. + # in a dictionary. @property def detailed_output(self): """Returns detailed phase information.""" From 9144cff95604112bf3537210d604b3b68830e81d Mon Sep 17 00:00:00 2001 From: Jake Nunemaker Date: Wed, 1 Mar 2023 14:16:08 -0700 Subject: [PATCH 18/19] Updated changelog and version. --- README.rst | 2 +- docs/source/changelog.rst | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index db11c217..bb4df5de 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,7 @@ ORBIT Offshore Renewables Balance of system and Installation Tool -:Version: 1.0.7 +:Version: 1.0.8 :Authors: `Jake Nunemaker `_, `Matt Shields `_, `Rob Hammond `_ :Documentation: `ORBIT Docs `_ diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 54f02f91..8386a2c4 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -3,6 +3,13 @@ ORBIT Changelog =============== +1.0.8 +----- + +- Added WOMBAT compatibility for custom array system files. +- Fixed bug in custom array cable system design that breaks for plants with + more than two substations. + 1.0.7 ----- From e88297e4cba699c7f52d9e26ccbecf3db19c25d3 Mon Sep 17 00:00:00 2001 From: Jake Nunemaker Date: Wed, 1 Mar 2023 14:18:00 -0700 Subject: [PATCH 19/19] Updated changelog --- docs/source/changelog.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 8386a2c4..07ab75f2 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -6,6 +6,8 @@ ORBIT Changelog 1.0.8 ----- +- Added explicit methods for adding custom design or install phases to + ProjectManager. - Added WOMBAT compatibility for custom array system files. - Fixed bug in custom array cable system design that breaks for plants with more than two substations.