Repository: NREL/HOPP (language: python)

Issue:
Onshore and Offshore Functionality
<!--
IMPORTANT NOTES

Is this pull request ready to be merged?
- Do the existing tests pass and new tests added for new code?
- Is all development in a state where you are proud to share it with others and
  willing to ask other people to take the time to review it?
- Is it documented in such a way that a review can reasonably understand what you've
  done and why you've done it? Can other users understand how to use your changes?
If not but opening the pull request will facilitate development, make it a "draft" pull request

This form is written in GitHub's Markdown format. For a reference on this type
of syntax, see GitHub's documentation:
https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax

This template contains guidance for your submission within the < ! - -, - - > blocks.
These are comments in HTML syntax and will not appear in the submission.
Be sure to use the "Preview" feature on GitHub to ensure your submission is formatted as intended.

When including code snippets, please paste the text itself and wrap the code block with
ticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.
For example, Python code should be wrapped in ticks like this:
```python
def a_func():
    return 1

a = 1
b = a_func()
print(a + b)
```
This is preferred over screen shots since it is searchable and others can copy/paste
the text to run it.
-->


# Modify ECO tools to allow for onshore wind functionality
<!--
Be sure to title your pull request so that readers can scan through the list of PR's and understand
what this one involves. It should be a few well selected words to get the point across. If you have
a hard time choosing a brief title, consider splitting the pull request into multiple pull requests.
Keep in mind that the title will be automatically included in the release notes.
-->

- Extract `ORBIT` as a required component of ECO tools.
- Add method for creating layout for onshore wind.
- Added `GreenHeartSimulationConfig` attrs class to `run_greenheart_simulation.py`

## Related issue
<!--
If one exists, link to a related GitHub Issue.
-->

## Impacted areas of the software
<!--
List any modules or other areas which should be impacted by this pull request. This helps to
determine the verification tests.
-->

## Additional supporting information
<!--
Add any other context about the problem here.
-->

## Test results, if applicable
<!--
Add the results from unit tests and regression tests here along with justification for any
failing test cases.
-->
`test_greenheart_system.py` is failing for onshore cases. Need to update values once full system is running.
<!--
__ For NREL use __
Release checklist:
- Update the version in
    - [ ] README.md
    - [ ] hopp/VERSION
- [ ] Verify docs builds correctly
- [ ] Create a tag in the NREL/HOPP repository
-->

Add documentation for ReadTheDocs



Discussion / hints:

Added initial skeleton, but still need to expand docs

Fix patch:
diff --git a/examples/greenheart/05-offshore-h2/greenheart-h2-offshore.py b/examples/greenheart/05-offshore-h2/greenheart-h2-offshore.py
index f8c616c71..8af9d9d22 100644
--- a/examples/greenheart/05-offshore-h2/greenheart-h2-offshore.py
+++ b/examples/greenheart/05-offshore-h2/greenheart-h2-offshore.py
@@ -7,15 +7,19 @@
 from pathlib import Path
 
 PATH = Path(__file__).parent
-YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir=PATH / './input/floris/')
-YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir=PATH / './input/turbines/')
+YamlIncludeConstructor.add_to_loader_class(
+    loader_class=yaml.FullLoader, base_dir=PATH / './input/floris/'
+)
+YamlIncludeConstructor.add_to_loader_class(
+    loader_class=yaml.FullLoader, base_dir=PATH / './input/turbines/'
+)
 
 # ORBIT imports
 from ORBIT.core.library import initialize_library
 initialize_library(os.path.join(os.getcwd(), "./input/"))
 
 # HOPP imports
-from greenheart.simulation.greenheart_simulation import run_simulation
+from greenheart.simulation.greenheart_simulation import run_simulation, GreenHeartSimulationConfig
 
 # run the stuff
 if __name__ == "__main__":
@@ -29,4 +33,18 @@
     filename_hopp_config = "./input/plant/hopp_config.yaml"
     filename_greenheart_config = "./input/plant/greenheart_config.yaml"
     
-    run_simulation(filename_hopp_config, filename_greenheart_config, filename_turbine_config, filename_orbit_config, filename_floris_config, verbose=True, show_plots=False, save_plots=True,  use_profast=True, incentive_option=1, plant_design_scenario=1)
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config,
+        filename_greenheart_config,
+        filename_turbine_config,
+        filename_orbit_config,
+        filename_floris_config,
+        verbose=True,
+        show_plots=False,
+        save_plots=True,
+        use_profast=True,
+        incentive_option=1,
+        plant_design_scenario=1
+    )
+
+    run_simulation(config)
diff --git a/examples/greenheart/05-offshore-h2/input/plant/greenheart_config.yaml b/examples/greenheart/05-offshore-h2/input/plant/greenheart_config.yaml
index d4a991c35..021fc258e 100644
--- a/examples/greenheart/05-offshore-h2/input/plant/greenheart_config.yaml
+++ b/examples/greenheart/05-offshore-h2/input/plant/greenheart_config.yaml
@@ -1,9 +1,17 @@
 site:
   mean_windspeed: False 
+  depth: 45 #m
+  wind_layout:
+    row_spacing: 7  # Also defined in ORBIT config for offshore layout. Will need to update and consolidate to hopefully HOPP config file. This row_spacing and turbine_spacing are used for onshore layout.
+    turbine_spacing: 7 # Also defined in ORBIT config for offshore layout. Will need to update and consolidate to hopefully HOPP config file. This row_spacing and turbine_spacing are used for onshore layout.
+    grid_angle: 0 # wind layout grid angle in degrees where 0 is north, increasing clockwise
+    row_phase_offset: 0 # wind layout offset of turbines along row from one row to the next
 project_parameters:
+  project_lifetime: 30
   grid_connection: False # option, can be turned on or off
   ppa_price: 0.025 # $/kWh based on 2022 land based wind market report (ERCOT area ppa prices) https://www.energy.gov/sites/default/files/2022-08/land_based_wind_market_report_2202.pdf
-  atb_year: 2022
+  atb_year: 2025
+  cost_year: 2022 # to match ATB
 finance_parameters:
   general_inflation: 0.025 # based on 2022 ATB
   discount_rate: 0.10 # nominal return based on 2022 ATB basline workbook
@@ -42,21 +50,12 @@ finance_parameters:
     h2_transport_pipeline: 2018 # same model for costs as the h2_pipe_array
   wind:
     expected_plant_cost: 'none'
-    
 electrolyzer:
   rating: 180 # MW # 0.9*Plant rating appears near-optimal for 400 MW wind plant with 3 days of underground pipe storage # MW
   electrolyzer_capex: 700 # $/kW conservative 2025 centralized. high 700, low 300 # based on https://www.irena.org/-/media/Files/IRENA/Agency/Publication/2020/Dec/IRENA_Green_hydrogen_cost_2020.pdf
   time_between_replacement: 62320 # 62320 based on PEM Electrolysis H2A Production Case Study Documentation estimate of 7 years, 40000 based on current est (see unpublished report), 80000 hours based on OSW atb_year = 2025
   replacement_cost_percent: 0.15 # percent of capex - H2A default case
   model: "singlitico2021" # "basic" is a basic cost model based on H2a and HFTO program record for PEM electrolysis. "singlitico2021" uses cost estimates from that paper
-  
-# h2_transport_compressor:
-#   output_pressure: 100 # bar (1 bar = 100 kPa)
-#   flow_rate: 89 # kg/hr
-#   energy_rating: 802 # kWe (aka 1 kWh)
-#   mean_days_between_failures: 200 # days
-#   useful_life: 15 # was default in compressor script
-#   # annual_h2_throughput: 18750 # [kg/yr] -> kg of H2 per year
 h2_transport_compressor:
   outlet_pressure: 68 # bar based on HDSAM
 h2_storage_compressor:
@@ -142,43 +141,69 @@ plant_design:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario1:
     electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario2:
     electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario3:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario4:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario5:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario6:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario7:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario8:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc+pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
-# design A -> scenario 1
-    # onshore electrolysis
-    # HVDC transport, HVDC_2000mm_320kV
-    # no storage
-# design B -> scenario 7
-    # electrolysis on platform
-    # pipe transport to shore
-    # no storage
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
+  scenario9:
+    electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
+    h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "onshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
\ No newline at end of file
diff --git a/examples/greenheart/05-offshore-h2/input/plant/hopp_config.yaml b/examples/greenheart/05-offshore-h2/input/plant/hopp_config.yaml
index 88bc355bd..da11ae7ea 100644
--- a/examples/greenheart/05-offshore-h2/input/plant/hopp_config.yaml
+++ b/examples/greenheart/05-offshore-h2/input/plant/hopp_config.yaml
@@ -7,14 +7,14 @@ site: #!include flatirons_site.yaml
     site_boundaries: 
       verts:  
         - [0.0, 0.0]
-        - [0.0, 2000.0]
-        - [2000.0, 2000.0]
-        - [2000.0, 0.0] 
+        - [0.0, 15000.0]
+        - [15000.0, 15000.0]
+        - [15000.0, 0.0] 
       verts_simple: 
         - [0.0, 0.0]
-        - [0.0, 2000.0]
-        - [2000.0, 2000.0]
-        - [2000.0, 0.0]
+        - [0.0, 15000.0]
+        - [15000.0, 15000.0]
+        - [15000.0, 0.0]
   solar_resource_file: ""
   wind_resource_file: "resource_files/wind/27.18624_-96.9516_windtoolkit_2013_60min_160m_200m.srw"
   wave_resource_file: ""
@@ -34,7 +34,12 @@ technologies:
     model_name: floris
     timestep: [0, 8760]
     floris_config: input_files/floris/floris_input_osw_18MW.yaml
-    fin_model: !include default_fin_config.yaml
+    fin_model:
+      system_costs:
+        om_fixed: 1
+      financial_parameters:
+        inflation_rate: 2.5
+        real_discount_rate: 6.4
   grid:
     interconnect_kw: 180000
     fin_model: !include default_fin_config.yaml
diff --git a/greenheart/simulation/greenheart_simulation.py b/greenheart/simulation/greenheart_simulation.py
index 82bc41e98..47a4b0559 100644
--- a/greenheart/simulation/greenheart_simulation.py
+++ b/greenheart/simulation/greenheart_simulation.py
@@ -1,19 +1,20 @@
 # general imports
 import os
 from typing import Optional
-
+import warnings
 import numpy as np
 import pandas as pd
+from attrs import define, field
+
+pd.options.mode.chained_assignment = None  # default='warn'
+
 from greenheart.simulation.technologies.ammonia.ammonia import (
     run_ammonia_full_model,
 )
-
 from greenheart.simulation.technologies.steel.steel import (
     run_steel_full_model,
 )
 
-pd.options.mode.chained_assignment = None  # default='warn'
-
 # visualization imports
 import matplotlib.pyplot as plt
 
@@ -24,118 +25,203 @@
 import greenheart.tools.eco.utilities as he_util
 import greenheart.tools.eco.hydrogen_mgmt as he_h2
 
-
-# set up function to run base line case
-def run_simulation(
-    filename_hopp_config,
-    filename_greenheart_config,
-    filename_turbine_config,
-    filename_orbit_config,
-    filename_floris_config,
-    electrolyzer_rating_mw=None,
-    solar_rating=None,
-    battery_capacity_kw=None,
-    battery_capacity_kwh=None,
-    wind_rating=None,
-    verbose=False,
-    show_plots=False,
-    save_plots=False,
-    use_profast=True,
-    post_processing=True,
-    storage_type=None,
-    incentive_option=1,
-    plant_design_scenario=1,
-    output_level=1,
-    grid_connection=None,
-):
-
-    # load inputs as needed
-    (
-        hopp_config,
-        greenheart_config,
-        orbit_config,
-        turbine_config,
-        floris_config,
-        orbit_hybrid_electrical_export_config,
-    ) = he_util.get_inputs(
-        filename_hopp_config,
-        filename_greenheart_config,
-        filename_orbit_config=filename_orbit_config,
-        filename_floris_config=filename_floris_config,
-        filename_turbine_config=filename_turbine_config,
-        verbose=verbose,
-        show_plots=show_plots,
-        save_plots=save_plots,
-    )
-
-    if electrolyzer_rating_mw != None:
-        greenheart_config["electrolyzer"]["flag"] = True
-        greenheart_config["electrolyzer"]["rating"] = electrolyzer_rating_mw
-
-    if solar_rating != None:
-        hopp_config["site"]["solar"] = True
-        hopp_config["technologies"]["pv"]["system_capacity_kw"] = solar_rating
-
-    if battery_capacity_kw != None:
-        hopp_config["site"]["battery"]["flag"] = True
-        hopp_config["technologies"]["battery"][
-            "system_capacity_kw"
-        ] = battery_capacity_kw
-
-    if battery_capacity_kwh != None:
-        hopp_config["site"]["battery"]["flag"] = True
-        hopp_config["technologies"]["battery"][
-            "system_capacity_kwh"
-        ] = battery_capacity_kwh
-
-    if storage_type != None:
-        greenheart_config["h2_storage"]["type"] = storage_type
-
-    if wind_rating != None:
-        orbit_config["plant"]["capacity"] = int(wind_rating * 1e-3)
-        orbit_config["plant"]["num_turbines"] = int(
-            wind_rating * 1e-3 / turbine_config["turbine_rating"]
+@define
+class GreenHeartSimulationConfig:
+    """
+    Class to hold all the configuration parameters for the GreenHeart model
+
+    Also sets up the HOPP, GreenHeart, ORBIT, and FLORIS configurations based on the
+    input files and configuration parameters passed in.
+
+    Args:
+        filename_hopp_config (str): filename for the HOPP configuration
+        filename_config.greenheart_config (str): filename for the GreenHeart configuration
+        filename_turbine_config (str): filename for the turbine configuration
+        filename_orbit_config (str): filename for the ORBIT configuration
+        filename_floris_config (str): filename for the FLORIS configuration
+        electrolyzer_rating_mw (Optional[float]): rating of the electrolyzer in MW
+        solar_rating (Optional[float]): rating of the solar plant in MW
+        battery_capacity_kw (Optional[float]): capacity of the battery in kW
+        battery_capacity_kwh (Optional[float]): capacity of the battery in kWh
+        wind_rating (Optional[float]): rating of the wind plant in MW
+        verbose (bool): flag to print verbose output
+        show_plots (bool): flag to show plots
+        save_plots (bool): flag to save plots
+        use_profast (bool): flag to use profast
+        post_processing (bool): flag to run post processing
+        storage_type (Optional[str]): type of storage
+        incentive_option (int): incentive option
+        plant_design_scenario (int): plant design scenario
+        output_level (int): output level
+        grid_connection (Optional[bool]): flag for grid connection
+    """
+
+    filename_hopp_config: str
+    filename_greenheart_config: str
+    filename_turbine_config: str
+    filename_orbit_config: str
+    filename_floris_config: str
+    electrolyzer_rating_mw: Optional[float] = field(default=None)
+    solar_rating: Optional[float] = field(default=None)
+    battery_capacity_kw: Optional[float] = field(default=None)
+    battery_capacity_kwh: Optional[float] = field(default=None)
+    wind_rating: Optional[float] = field(default=None)
+    verbose: bool = field(default=False)
+    show_plots: bool = field(default=False)
+    save_plots: bool = field(default=False)
+    use_profast: bool = field(default=True)
+    post_processing: bool = field(default=True)
+    storage_type: Optional[str] = field(default=None)
+    incentive_option: int = field(default=1)
+    plant_design_scenario: int = field(default=1)
+    output_level: int = field(default=1)
+    grid_connection: Optional[bool] = field(default=None)
+
+    # these are set in the __attrs_post_init__ method
+    hopp_config: dict = field(init=False)
+    greenheart_config: dict = field(init=False)
+    orbit_config: dict = field(init=False)
+    turbine_config: dict = field(init=False)
+    floris_config: Optional[dict] = field(init=False)
+    orbit_hybrid_electrical_export_config: dict = field(init=False)
+    design_scenario: dict = field(init=False)
+
+    def __attrs_post_init__(self):
+        (
+            self.hopp_config,
+            self.greenheart_config,
+            self.orbit_config,
+            self.turbine_config,
+            self.floris_config,
+            self.orbit_hybrid_electrical_export_config,
+        ) = he_util.get_inputs(
+            self.filename_hopp_config,
+            self.filename_greenheart_config,
+            filename_orbit_config=self.filename_orbit_config,
+            filename_floris_config=self.filename_floris_config,
+            filename_turbine_config=self.filename_turbine_config,
+            verbose=self.verbose,
+            show_plots=self.show_plots,
+            save_plots=self.save_plots,
         )
-        hopp_config["technologies"]["wind"]["num_turbines"] = orbit_config["plant"][
-            "num_turbines"
-        ]
 
-    if grid_connection != None:
-        greenheart_config["project_parameters"]["grid_connection"] = grid_connection
-        if grid_connection:
-            hopp_config["technologies"]["grid"]["interconnect_kw"] = (
-                orbit_config["plant"]["capacity"] * 1e6
+        # n scenarios, n discrete variables
+        self.design_scenario = self.greenheart_config["plant_design"][
+            "scenario%s" % (self.plant_design_scenario)
+        ]
+        self.design_scenario["id"] = self.plant_design_scenario
+
+        # if design_scenario["h2_storage_location"] == "turbine":
+        #     plant_config["h2_storage"]["type"] = "turbine"
+
+        if self.electrolyzer_rating_mw != None:
+            self.greenheart_config["electrolyzer"]["flag"] = True
+            self.greenheart_config["electrolyzer"][
+                "rating"
+            ] = self.electrolyzer_rating_mw
+
+        if self.solar_rating != None:
+            self.hopp_config["site"]["solar"] = True
+            self.hopp_config["technologies"]["pv"][
+                "system_capacity_kw"
+            ] = self.solar_rating
+
+        if self.battery_capacity_kw != None:
+            self.hopp_config["site"]["battery"]["flag"] = True
+            self.hopp_config["technologies"]["battery"][
+                "system_capacity_kw"
+            ] = self.battery_capacity_kw
+
+        if self.battery_capacity_kwh != None:
+            self.hopp_config["site"]["battery"]["flag"] = True
+            self.hopp_config["technologies"]["battery"][
+                "system_capacity_kwh"
+            ] = self.battery_capacity_kwh
+
+        if self.storage_type != None:
+            self.greenheart_config["h2_storage"]["type"] = self.storage_type
+
+        if self.wind_rating != None:
+            self.orbit_config["plant"]["capacity"] = int(self.wind_rating * 1e-3)
+            self.orbit_config["plant"]["num_turbines"] = int(
+                self.wind_rating * 1e-3 / self.turbine_config["turbine_rating"]
             )
+            self.hopp_config["technologies"]["wind"]["num_turbines"] = (
+                self.orbit_config["plant"]["num_turbines"]
+            )
+        
+        if self.grid_connection != None:
+            self.greenheart_config["project_parameters"][
+                "grid_connection"
+            ] = self.grid_connection
+            if self.grid_connection:
+                self.hopp_config["technologies"]["grid"]["interconnect_kw"] = (
+                    self.orbit_config["plant"]["capacity"] * 1e6
+                )
 
-    # 7 scenarios, 3 discrete variables
-    design_scenario = greenheart_config["plant_design"][
-        "scenario%s" % (plant_design_scenario)
-    ]
-    design_scenario["id"] = plant_design_scenario
-
-    # if design_scenario["h2_storage_location"] == "turbine":
-    #     plant_config["h2_storage"]["type"] = "turbine"
-
+def run_simulation(config: GreenHeartSimulationConfig):
     # run orbit for wind plant construction and other costs
     ## TODO get correct weather (wind, wave) inputs for ORBIT input (possibly via ERA5)
-    orbit_project, orbit_hybrid_electrical_export_project = he_fin.run_orbit(
-        orbit_config,
-        weather=None,
-        verbose=verbose,
-        orbit_hybrid_electrical_export_config=orbit_hybrid_electrical_export_config,
-    )
 
+    if config.design_scenario["wind_location"] == "offshore":
+        
+        if config.orbit_config["plant"]["num_turbines"] != config.hopp_config["technologies"]["wind"]["num_turbines"]:
+            config.orbit_config["plant"].update(
+                {"num_turbines": config.hopp_config["technologies"]["wind"]["num_turbines"]}
+            )
+            warnings.warn(f"'num_turbines' in the orbit_config was {config.orbit_config['plant']['num_turbines']}, but 'num_turbines' in" 
+                    f"hopp_config was {config.hopp_config['technologies']['wind']['num_turbines']}. The 'num_turbines' value in the orbit_config"
+                    "is being overwritten with the value from the hopp_config", UserWarning)
+            
+        if config.orbit_config["site"]["depth"] != config.greenheart_config["site"]["depth"]:
+            config.orbit_config["site"].update(
+                {"depth": config.greenheart_config["site"]["depth"]}
+            )
+            warnings.warn(f"site depth in the orbit_config was {config.orbit_config['site']['depth']}, but site depth in" 
+                    f"greenheart_config was {config.greenheart_config['site']['depth']}. The site depth value in the orbit_config"
+                    "is being overwritten with the value from the greenheart_config", UserWarning)
+            
+        if config.orbit_config["plant"]["turbine_spacing"] != config.greenheart_config["site"]["wind_layout"]["turbine_spacing"]:
+            config.orbit_config["plant"].update(
+                {"turbine_spacing": config.greenheart_config["site"]["wind_layout"]["turbine_spacing"]}
+            )
+            warnings.warn(f"site depth in the orbit_config was {config.orbit_config['plant']['turbine_spacing']}, but 'turbine_spacing' in" 
+                    f"greenheart_config was {config.greenheart_config['site']['wind_layout']['turbine_spacing']}. The 'turbine_spacing' value in the orbit_config"
+                    "is being overwritten with the value from the greenheart_config", UserWarning)
+            
+        if config.orbit_config["plant"]["row_spacing"] != config.greenheart_config["site"]["wind_layout"]["row_spacing"]:
+            config.orbit_config["plant"].update(
+                {"row_spacing": config.greenheart_config["site"]["wind_layout"]["row_spacing"]}
+            )
+            warnings.warn(f"site depth in the orbit_config was {config.orbit_config['plant']['row_spacing']}, but 'row_spacing' in" 
+                    f"greenheart_config was {config.greenheart_config['site']['wind_layout']['row_spacing']}. The 'row_spacing' value in the orbit_config"
+                    "is being overwritten with the value from the greenheart_config", UserWarning)
+
+        wind_config = he_fin.WindCostConfig(
+            design_scenario=config.design_scenario,
+            hopp_config=config.hopp_config,
+            greenheart_config=config.greenheart_config,
+            orbit_config=config.orbit_config,
+            orbit_hybrid_electrical_export_config=config.orbit_hybrid_electrical_export_config,
+        )
+
+        wind_cost_results = he_fin.run_wind_cost_model(
+            wind_cost_inputs=wind_config, verbose=config.verbose
+        )
+    else:
+        wind_cost_results = None
+        
     # setup HOPP model
-    # hopp_site, hopp_technologies, hopp_scenario, hopp_h2_args = he_hopp.setup_hopp(hopp_config, greenheart_config, orbit_config, turbine_config, orbit_project, floris_config, show_plots=show_plots, save_plots=save_plots)
     hopp_config, hopp_site = he_hopp.setup_hopp(
-        hopp_config,
-        greenheart_config,
-        orbit_config,
-        turbine_config,
-        orbit_project,
-        floris_config,
-        show_plots=show_plots,
-        save_plots=save_plots,
+        config.hopp_config,
+        config.greenheart_config,
+        config.orbit_config,
+        config.turbine_config,
+        config.floris_config,
+        config.design_scenario,
+        wind_cost_results,
+        show_plots=config.show_plots,
+        save_plots=config.save_plots,
     )
 
     # run HOPP model
@@ -143,23 +229,38 @@ def run_simulation(
     hopp_results = he_hopp.run_hopp(
         hopp_config,
         hopp_site,
-        project_lifetime=orbit_config["project_parameters"]["project_lifetime"],
-        verbose=verbose,
+        project_lifetime=config.greenheart_config["project_parameters"][
+            "project_lifetime"
+        ],
+        verbose=config.verbose,
     )
 
+    if config.design_scenario["wind_location"] == "onshore":
+        wind_config = he_fin.WindCostConfig(
+            design_scenario=config.design_scenario,
+            hopp_config=config.hopp_config,
+            greenheart_config=config.greenheart_config,
+            turbine_config=config.turbine_config,
+            hopp_interface=hopp_results["hopp_interface"]
+        )
+
+        wind_cost_results = he_fin.run_wind_cost_model(
+            wind_cost_inputs=wind_config, verbose=config.verbose
+        )
+
     # this portion of the system is inside a function so we can use a solver to determine the correct energy availability for h2 production
     def energy_internals(
         hopp_results=hopp_results,
-        orbit_project=orbit_project,
-        design_scenario=design_scenario,
-        orbit_config=orbit_config,
+        wind_cost_results=wind_cost_results,
+        design_scenario=config.design_scenario,
+        orbit_config=config.orbit_config,
         hopp_config=hopp_config,
-        greenheart_config=greenheart_config,
-        turbine_config=turbine_config,
+        greenheart_config=config.greenheart_config,
+        turbine_config=config.turbine_config,
         wind_resource=hopp_site.wind_resource,
-        verbose=verbose,
-        show_plots=show_plots,
-        save_plots=save_plots,
+        verbose=config.verbose,
+        show_plots=config.show_plots,
+        save_plots=config.save_plots,
         solver=True,
         power_for_peripherals_kw_in=0.0,
         breakdown=False,
@@ -194,8 +295,7 @@ def energy_internals(
         # run electrolyzer physics model
         electrolyzer_physics_results = he_elec.run_electrolyzer_physics(
             hopp_results_internal,
-            orbit_config["project_parameters"]["project_lifetime"],
-            greenheart_config,
+            config.greenheart_config,
             wind_resource,
             design_scenario,
             show_plots=show_plots,
@@ -206,21 +306,22 @@ def energy_internals(
         # run electrolyzer cost model
         electrolyzer_cost_results = he_elec.run_electrolyzer_cost(
             electrolyzer_physics_results,
-            orbit_config,
             hopp_config,
-            greenheart_config,
+            config.greenheart_config,
             design_scenario,
             verbose=verbose,
         )
 
         desal_results = he_elec.run_desal(
-            orbit_config, electrolyzer_physics_results, design_scenario, verbose
+            hopp_config, electrolyzer_physics_results, design_scenario, verbose
         )
 
         # run array system model
         h2_pipe_array_results = he_h2.run_h2_pipe_array(
-            orbit_config,
-            orbit_project,
+            greenheart_config,
+            hopp_config,
+            turbine_config,
+            wind_cost_results,
             electrolyzer_physics_results,
             design_scenario,
             verbose,
@@ -229,7 +330,7 @@ def energy_internals(
         # compressor #TODO size correctly
         h2_transport_compressor, h2_transport_compressor_results = (
             he_h2.run_h2_transport_compressor(
-                greenheart_config,
+                config.greenheart_config,
                 electrolyzer_physics_results,
                 design_scenario,
                 verbose=verbose,
@@ -237,17 +338,23 @@ def energy_internals(
         )
 
         # transport pipeline
-        h2_transport_pipe_results = he_h2.run_h2_transport_pipe(
-            orbit_config,
-            greenheart_config,
-            electrolyzer_physics_results,
-            design_scenario,
-            verbose=verbose,
-        )
+        if design_scenario["wind_location"] == "offshore":
+            h2_transport_pipe_results = he_h2.run_h2_transport_pipe(
+                orbit_config,
+                greenheart_config,
+                electrolyzer_physics_results,
+                design_scenario,
+                verbose=verbose,
+            )
+        if design_scenario["wind_location"] == "onshore":
+            h2_transport_pipe_results = {
+                "total capital cost [$]": [0 * 5433290.0184895478],
+                "annual operating cost [$]": [0.0],
+            }
 
         # pressure vessel storage
         pipe_storage, h2_storage_results = he_h2.run_h2_storage(
-            orbit_config,
+            hopp_config,
             greenheart_config,
             turbine_config,
             electrolyzer_physics_results,
@@ -438,14 +545,14 @@ def simple_solver(initial_guess=0.0):
     ## end solver loop here
     platform_results = he_h2.run_equipment_platform(
         hopp_config,
-        greenheart_config,
-        orbit_config,
-        design_scenario,
+        config.greenheart_config,
+        config.orbit_config,
+        config.design_scenario,
         hopp_results,
         electrolyzer_physics_results,
         h2_storage_results,
         desal_results,
-        verbose=verbose,
+        verbose=config.verbose,
     )
 
     ################# OSW intermediate calculations" aka final financial calculations
@@ -457,42 +564,38 @@ def simple_solver(initial_guess=0.0):
     # TODO double check full-system CAPEX
     capex, capex_breakdown = he_fin.run_capex(
         hopp_results,
-        orbit_project,
-        orbit_hybrid_electrical_export_project,
+        wind_cost_results,
         electrolyzer_cost_results,
         h2_pipe_array_results,
         h2_transport_compressor_results,
         h2_transport_pipe_results,
         h2_storage_results,
         hopp_config,
-        greenheart_config,
-        orbit_config,
-        design_scenario,
+        config.greenheart_config,
+        config.design_scenario,
         desal_results,
         platform_results,
-        verbose=verbose,
+        verbose=config.verbose,
     )
 
     # TODO double check full-system OPEX
     opex_annual, opex_breakdown_annual = he_fin.run_opex(
         hopp_results,
-        orbit_project,
-        orbit_hybrid_electrical_export_project,
+        wind_cost_results,
         electrolyzer_cost_results,
         h2_pipe_array_results,
         h2_transport_compressor_results,
         h2_transport_pipe_results,
         h2_storage_results,
         hopp_config,
-        greenheart_config,
-        orbit_config,
+        config.greenheart_config,
         desal_results,
         platform_results,
-        verbose=verbose,
+        verbose=config.verbose,
         total_export_system_cost=capex_breakdown["electrical_export_system"],
     )
 
-    if verbose:
+    if config.verbose:
         print(
             "hybrid plant capacity factor: ",
             np.sum(hopp_results["combined_hybrid_power_production_hopp"])
@@ -502,90 +605,93 @@ def simple_solver(initial_guess=0.0):
     steel_finance = None
     ammonia_finance = None
 
-    if use_profast:
+    if config.use_profast:
         lcoe, pf_lcoe = he_fin.run_profast_lcoe(
-            greenheart_config,
-            orbit_config,
-            orbit_project,
+            config.greenheart_config,
+            wind_cost_results,
             capex_breakdown,
             opex_breakdown_annual,
             hopp_results,
-            incentive_option,
-            design_scenario,
-            verbose=verbose,
-            show_plots=show_plots,
-            save_plots=save_plots,
+            config.incentive_option,
+            config.design_scenario,
+            verbose=config.verbose,
+            show_plots=config.show_plots,
+            save_plots=config.save_plots,
         )
         lcoh_grid_only, pf_grid_only = he_fin.run_profast_grid_only(
-            greenheart_config,
-            orbit_config,
-            orbit_project,
+            config.greenheart_config,
+            wind_cost_results,
             electrolyzer_physics_results,
             capex_breakdown,
             opex_breakdown_annual,
             hopp_results,
-            design_scenario,
+            config.design_scenario,
             total_accessory_power_renewable_kw,
             total_accessory_power_grid_kw,
-            verbose=verbose,
-            show_plots=show_plots,
-            save_plots=save_plots,
+            verbose=config.verbose,
+            show_plots=config.show_plots,
+            save_plots=config.save_plots,
         )
         lcoh, pf_lcoh = he_fin.run_profast_full_plant_model(
-            greenheart_config,
-            orbit_config,
-            orbit_project,
+            config.greenheart_config,
+            wind_cost_results,
             electrolyzer_physics_results,
             capex_breakdown,
             opex_breakdown_annual,
             hopp_results,
-            incentive_option,
-            design_scenario,
+            config.incentive_option,
+            config.design_scenario,
             total_accessory_power_renewable_kw,
             total_accessory_power_grid_kw,
-            verbose=verbose,
-            show_plots=show_plots,
-            save_plots=save_plots,
+            verbose=config.verbose,
+            show_plots=config.show_plots,
+            save_plots=config.save_plots,
         )
 
         hydrogen_amount_kgpy = electrolyzer_physics_results["H2_Results"][
             "hydrogen_annual_output"
         ]
 
-        if "steel" in greenheart_config:
-            if verbose:
+        if "steel" in config.greenheart_config:
+            if config.verbose:
                 print("Running steel\n")
 
             # use lcoh from the electrolyzer model if it is not already in the config
-            if "lcoh" not in greenheart_config["steel"]["finances"]:
-                greenheart_config["steel"]["finances"]["lcoh"] = lcoh
+            if "lcoh" not in config.greenheart_config["steel"]["finances"]:
+                config.greenheart_config["steel"]["finances"]["lcoh"] = lcoh
 
             # use lcoh from the electrolyzer model if it is not already in the config
-            if "lcoh" not in greenheart_config["steel"]["costs"]:
-                greenheart_config["steel"]["costs"]["lcoh"] = lcoh
+            if "lcoh" not in config.greenheart_config["steel"]["costs"]:
+                config.greenheart_config["steel"]["costs"]["lcoh"] = lcoh
 
             # use the hydrogen amount from the electrolyzer physics model if it is not already in the config
-            if "hydrogen_amount_kgpy" not in greenheart_config["steel"]["capacity"]:
-                greenheart_config["steel"]["capacity"][
+            if (
+                "hydrogen_amount_kgpy"
+                not in config.greenheart_config["steel"]["capacity"]
+            ):
+                config.greenheart_config["steel"]["capacity"][
                     "hydrogen_amount_kgpy"
                 ] = hydrogen_amount_kgpy
 
-            _, _, steel_finance = run_steel_full_model(greenheart_config)
+            _, _, steel_finance = run_steel_full_model(config.greenheart_config)
 
-        if "ammonia" in greenheart_config:
-            if verbose:
+        if "ammonia" in config.greenheart_config:
+            if config.verbose:
                 print("Running ammonia\n")
 
             # use the hydrogen amount from the electrolyzer physics model if it is not already in the config
-            if "hydrogen_amount_kgpy" not in greenheart_config["ammonia"]["capacity"]:
-                greenheart_config["ammonia"]["capacity"][
+            if (
+                "hydrogen_amount_kgpy"
+                not in config.greenheart_config["ammonia"]["capacity"]
+            ):
+                config.greenheart_config["ammonia"]["capacity"][
                     "hydrogen_amount_kgpy"
                 ] = hydrogen_amount_kgpy
 
-            _, _, ammonia_finance = run_ammonia_full_model(greenheart_config)
+            _, _, ammonia_finance = run_ammonia_full_model(config.greenheart_config)
 
     ################# end OSW intermediate calculations
-    if post_processing:
+    if config.post_processing:
         power_breakdown = he_util.post_process_simulation(
             lcoe,
             lcoh,
@@ -594,29 +700,29 @@ def simple_solver(initial_guess=0.0):
             hopp_results,
             electrolyzer_physics_results,
             hopp_config,
-            greenheart_config,
-            orbit_config,
+            config.greenheart_config,
+            config.orbit_config,
             h2_storage_results,
             capex_breakdown,
             opex_breakdown_annual,
-            orbit_project,
+            wind_cost_results,
             platform_results,
             desal_results,
-            design_scenario,
-            plant_design_scenario,
-            incentive_option,
+            config.design_scenario,
+            config.plant_design_scenario,
+            config.incentive_option,
             solver_results=solver_results,
-            show_plots=show_plots,
-            save_plots=save_plots,
-            verbose=verbose,
+            show_plots=config.show_plots,
+            save_plots=config.save_plots,
+            verbose=config.verbose,
         )  # , lcoe, lcoh, lcoh_with_grid, lcoh_grid_only)
 
     # return
-    if output_level == 0:
+    if config.output_level == 0:
         return 0
-    elif output_level == 1:
+    elif config.output_level == 1:
         return lcoh
-    elif output_level == 2:
+    elif config.output_level == 2:
         return (
             lcoh,
             lcoe,
@@ -625,7 +731,7 @@ def simple_solver(initial_guess=0.0):
             pf_lcoh,
             electrolyzer_physics_results,
         )
-    elif output_level == 3:
+    elif config.output_level == 3:
         return (
             lcoh,
             lcoe,
@@ -636,13 +742,13 @@ def simple_solver(initial_guess=0.0):
             pf_lcoe,
             power_breakdown,
         )
-    elif output_level == 4:
+    elif config.output_level == 4:
         return lcoe, lcoh, lcoh_grid_only
-    elif output_level == 5:
+    elif config.output_level == 5:
         return lcoe, lcoh, lcoh_grid_only, hopp_results["hopp_interface"]
-    elif output_level == 6:
+    elif config.output_level == 6:
         return hopp_results, electrolyzer_physics_results, remaining_power_profile
-    elif output_level == 7:
+    elif config.output_level == 7:
         return lcoe, lcoh, steel_finance, ammonia_finance
 
 
diff --git a/greenheart/tools/eco/electrolysis.py b/greenheart/tools/eco/electrolysis.py
index 425a9780d..f2f0fcb9d 100644
--- a/greenheart/tools/eco/electrolysis.py
+++ b/greenheart/tools/eco/electrolysis.py
@@ -5,22 +5,32 @@
 
 # import hopp.tools.hopp_tools as hopp_tools
 
-from greenheart.simulation.technologies.hydrogen.desal.desal_model_eco import RO_desal_eco as RO_desal
+from greenheart.simulation.technologies.hydrogen.desal.desal_model_eco import (
+    RO_desal_eco as RO_desal,
+)
 from greenheart.simulation.technologies.hydrogen.electrolysis.pem_mass_and_footprint import (
     mass as run_electrolyzer_mass,
 )
 from greenheart.simulation.technologies.hydrogen.electrolysis.pem_mass_and_footprint import (
     footprint as run_electrolyzer_footprint,
 )
-from greenheart.simulation.technologies.hydrogen.electrolysis.H2_cost_model import basic_H2_cost_model
-from greenheart.simulation.technologies.hydrogen.electrolysis.PEM_costs_Singlitico_model import PEMCostsSingliticoModel
+from greenheart.simulation.technologies.hydrogen.electrolysis.H2_cost_model import (
+    basic_H2_cost_model,
+)
+from greenheart.simulation.technologies.hydrogen.electrolysis.PEM_costs_Singlitico_model import (
+    PEMCostsSingliticoModel,
+)
+
 # from hopp.simulation.technologies.hydrogen.electrolysis.run_h2_PEM_eco import run_h2_PEM
-from greenheart.simulation.technologies.hydrogen.electrolysis.run_h2_PEM import run_h2_PEM
+from greenheart.simulation.technologies.hydrogen.electrolysis.run_h2_PEM import (
+    run_h2_PEM,
+)
+
 # from electrolyzer import run_electrolyzer
 
+
 def run_electrolyzer_physics(
     hopp_results,
-    useful_life,
     greenheart_config,
     wind_resource,
     design_scenario,
@@ -28,46 +38,52 @@ def run_electrolyzer_physics(
     save_plots=False,
     verbose=False,
 ):
-    
 
     electrolyzer_size_mw = greenheart_config["electrolyzer"]["rating"]
     electrolyzer_capex_kw = greenheart_config["electrolyzer"]["electrolyzer_capex"]
-    
+
     if greenheart_config["project_parameters"]["grid_connection"]:
-        energy_to_electrolyzer_kw = np.ones(365 * 24 - 4*7*12) * ( # TODO why the subtraction here?
+        energy_to_electrolyzer_kw = np.ones(
+            365 * 24 - 4 * 7 * 12
+        ) * (  # TODO why the subtraction here?
             electrolyzer_size_mw * 1e3
         )
     else:
-        energy_to_electrolyzer_kw = np.asarray(hopp_results[
-            "combined_hybrid_power_production_hopp"
-        ])
+        energy_to_electrolyzer_kw = np.asarray(
+            hopp_results["combined_hybrid_power_production_hopp"]
+        )
     # calculate utilization rate
     energy_capacity = electrolyzer_size_mw * 365 * 24  # MWh
     energy_available = sum(energy_to_electrolyzer_kw) * 1e-3  # MWh
     capacity_factor_electrolyzer = energy_available / energy_capacity
 
     ## run using greensteel model
-    pem_param_dict = {"Modify EOL Degradation Value": False,
-                      "EOL Rated Efficiency Drop": 0.1,
-                      "Modify BOL Eff": False,
-                      "BOL Eff [kWh/kg-H2]": 0.95}
-    
-    #TODO get electrolyzer params from input yaml
-    H2_Results, h2_ts, h2_tot, energy_input_to_electrolyzer = run_h2_PEM(electrical_generation_timeseries=energy_to_electrolyzer_kw, 
-               electrolyzer_size=electrolyzer_size_mw,
-               useful_life=useful_life, # EG: should be in years for full plant life - only used in financial model
-               n_pem_clusters=1,  
-               electrolysis_scale=None, 
-               pem_control_type="simple",
-               electrolyzer_direct_cost_kw=electrolyzer_capex_kw, 
-               user_defined_pem_param_dictionary=pem_param_dict,
-               use_degradation_penalty=True, 
-               grid_connection_scenario='off-grid', # if not offgrid, assumes stead h2 demand in kgphr for full year
-               hydrogen_production_capacity_required_kgphr=0,
-               debug_mode = False,
-               turndown_ratio = 0.1,
-               verbose=verbose
-               )
+    pem_param_dict = {
+        "Modify EOL Degradation Value": False,
+        "EOL Rated Efficiency Drop": 0.1,
+        "Modify BOL Eff": False,
+        "BOL Eff [kWh/kg-H2]": 0.95,
+    }
+
+    # TODO get electrolyzer params from input yaml
+    H2_Results, h2_ts, h2_tot, energy_input_to_electrolyzer = run_h2_PEM(
+        electrical_generation_timeseries=energy_to_electrolyzer_kw,
+        electrolyzer_size=electrolyzer_size_mw,
+        useful_life=greenheart_config["project_parameters"][
+            "project_lifetime"
+        ],  # EG: should be in years for full plant life - only used in financial model
+        n_pem_clusters=1,
+        electrolysis_scale=None,
+        pem_control_type="simple",
+        electrolyzer_direct_cost_kw=electrolyzer_capex_kw,
+        user_defined_pem_param_dictionary=pem_param_dict,
+        use_degradation_penalty=True,
+        grid_connection_scenario="off-grid",  # if not offgrid, assumes stead h2 demand in kgphr for full year
+        hydrogen_production_capacity_required_kgphr=0,
+        debug_mode=False,
+        turndown_ratio=0.1,
+        verbose=verbose,
+    )
 
     # calculate mass and foorprint of system
     mass_kg = run_electrolyzer_mass(electrolyzer_size_mw)
@@ -85,7 +101,10 @@ def run_electrolyzer_physics(
 
     if verbose:
         print("\nElectrolyzer Physics:")  # 61837444.34555772 145297297.29729727
-        print("H2 Produced Annually (tonnes): ", H2_Results["hydrogen_annual_output"]*1E-3)
+        print(
+            "H2 Produced Annually (tonnes): ",
+            H2_Results["hydrogen_annual_output"] * 1e-3,
+        )
         print(
             "Max H2 hourly (tonnes): ",
             max(H2_Results["hydrogen_hourly_production"]) * 1e-3,
@@ -146,7 +165,7 @@ def run_electrolyzer_physics(
         ax[0, 0].plot(wind_speed)
         convolved_wind_speed = np.convolve(wind_speed, np.ones(N) / (N), mode="valid")
         ave_x = range(N, len(convolved_wind_speed) + N)
-        
+
         ax[0, 1].plot(ave_x, convolved_wind_speed)
         ax[0, 0].set(ylabel="Wind\n(m/s)", ylim=[0, 30], xlim=[0, len(wind_speed)])
         tick_spacing = 10
@@ -162,19 +181,21 @@ def run_electrolyzer_physics(
             ),
         )
         ax[1, 1].axhline(y=y, color="r", linestyle="--", label="Nameplate Capacity")
-        ax[1, 0].set(ylabel="Electrolyzer \nPower (MW)", ylim=[0, 500], xlim=[0, len(wind_speed)])
+        ax[1, 0].set(
+            ylabel="Electrolyzer \nPower (MW)", ylim=[0, 500], xlim=[0, len(wind_speed)]
+        )
         # ax[1].legend(frameon=False, loc="best")
         tick_spacing = 200
         ax[1, 0].yaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
-        ax[1, 0].text(1000, y + 0.1*tick_spacing, "Electrolyzer Rating", color="r")
-
+        ax[1, 0].text(1000, y + 0.1 * tick_spacing, "Electrolyzer Rating", color="r")
 
-
-        ax[2, 0].plot(H2_Results["hydrogen_hourly_production"]*1E-3)
+        ax[2, 0].plot(H2_Results["hydrogen_hourly_production"] * 1e-3)
         ax[2, 1].plot(
             ave_x[:-1],
             np.convolve(
-                H2_Results["hydrogen_hourly_production"]*1E-3, np.ones(N) / (N), mode="valid"
+                H2_Results["hydrogen_hourly_production"] * 1e-3,
+                np.ones(N) / (N),
+                mode="valid",
             ),
         )
         tick_spacing = 2
@@ -196,16 +217,13 @@ def run_electrolyzer_physics(
         )
         ax[2, 1].yaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
 
-
-
         plt.tight_layout()
         if save_plots:
             savepath = "figures/production/"
             if not os.path.exists(savepath):
                 os.makedirs(savepath)
             plt.savefig(
-                savepath+"production_overview_%i.png"
-                % (design_scenario["id"]),
+                savepath + "production_overview_%i.png" % (design_scenario["id"]),
                 transparent=True,
             )
         if show_plots:
@@ -213,26 +231,28 @@ def run_electrolyzer_physics(
 
     return electrolyzer_physics_results
 
+
 def run_electrolyzer_cost(
     electrolyzer_physics_results,
-    orbit_config,
     hopp_config,
     greenheart_config,
     design_scenario,
-    verbose=False
+    verbose=False,
 ):
 
     # unpack inputs
     H2_Results = electrolyzer_physics_results["H2_Results"]
     electrolyzer_size_mw = greenheart_config["electrolyzer"]["rating"]
-    useful_life = orbit_config["project_parameters"]["project_lifetime"]
-    atb_year = orbit_config["atb_year"]
+    useful_life = greenheart_config["project_parameters"]["project_lifetime"]
+    atb_year = greenheart_config["project_parameters"]["atb_year"]
     electrical_generation_timeseries = electrolyzer_physics_results[
         "electrical_generation_timeseries"
     ]
     nturbines = hopp_config["technologies"]["wind"]["num_turbines"]
 
-    electrolyzer_cost_model = greenheart_config["electrolyzer"]["model"] # can be "basic" or "singlitico2021"
+    electrolyzer_cost_model = greenheart_config["electrolyzer"][
+        "model"
+    ]  # can be "basic" or "singlitico2021"
 
     # run hydrogen production cost model - from hopp examples
     if design_scenario["electrolyzer_location"] == "onshore":
@@ -272,15 +292,24 @@ def run_electrolyzer_cost(
 
         elif electrolyzer_cost_model == "singlitico2021":
 
-            P_elec =  per_turb_electrolyzer_size_mw*1E-3 # [GW]
-            RC_elec = greenheart_config["electrolyzer"]["electrolyzer_capex"] # [USD/kW]
+            P_elec = per_turb_electrolyzer_size_mw * 1e-3  # [GW]
+            RC_elec = greenheart_config["electrolyzer"][
+                "electrolyzer_capex"
+            ]  # [USD/kW]
 
             pem_offshore = PEMCostsSingliticoModel(elec_location=offshore)
 
-            per_turb_electrolyzer_capital_cost_musd, per_turb_electrolyzer_om_cost_musd = pem_offshore.run(P_elec, RC_elec)
+            (
+                per_turb_electrolyzer_capital_cost_musd,
+                per_turb_electrolyzer_om_cost_musd,
+            ) = pem_offshore.run(P_elec, RC_elec)
 
-            per_turb_electrolyzer_total_capital_cost = per_turb_electrolyzer_capital_cost_musd*1E6 # convert from M USD to USD
-            per_turb_electrolyzer_OM_cost = per_turb_electrolyzer_om_cost_musd*1E6 # convert from M USD to USD
+            per_turb_electrolyzer_total_capital_cost = (
+                per_turb_electrolyzer_capital_cost_musd * 1e6
+            )  # convert from M USD to USD
+            per_turb_electrolyzer_OM_cost = (
+                per_turb_electrolyzer_om_cost_musd * 1e6
+            )  # convert from M USD to USD
 
         electrolyzer_total_capital_cost = (
             per_turb_electrolyzer_total_capital_cost * nturbines
@@ -312,18 +341,31 @@ def run_electrolyzer_cost(
             )
         elif electrolyzer_cost_model == "singlitico2021":
 
-            P_elec =  electrolyzer_size_mw*1E-3 # [GW]
-            RC_elec = greenheart_config["electrolyzer"]["electrolyzer_capex"] # [USD/kW]
+            P_elec = electrolyzer_size_mw * 1e-3  # [GW]
+            RC_elec = greenheart_config["electrolyzer"][
+                "electrolyzer_capex"
+            ]  # [USD/kW]
 
             pem_offshore = PEMCostsSingliticoModel(elec_location=offshore)
 
-            electrolyzer_capital_cost_musd, electrolyzer_om_cost_musd = pem_offshore.run(P_elec, RC_elec)
+            electrolyzer_capital_cost_musd, electrolyzer_om_cost_musd = (
+                pem_offshore.run(P_elec, RC_elec)
+            )
 
-            electrolyzer_total_capital_cost = electrolyzer_capital_cost_musd*1E6 # convert from M USD to USD
-            electrolyzer_OM_cost = electrolyzer_om_cost_musd*1E6 # convert from M USD to USD
+            electrolyzer_total_capital_cost = (
+                electrolyzer_capital_cost_musd * 1e6
+            )  # convert from M USD to USD
+            electrolyzer_OM_cost = (
+                electrolyzer_om_cost_musd * 1e6
+            )  # convert from M USD to USD
 
         else:
-            raise(ValueError("Electrolyzer cost model must be one of['basic', 'singlitico2021'] but '%s' was given" % (electrolyzer_cost_model)))
+            raise (
+                ValueError(
+                    "Electrolyzer cost model must be one of['basic', 'singlitico2021'] but '%s' was given"
+                    % (electrolyzer_cost_model)
+                )
+            )
 
     # package outputs for return
     electrolyzer_cost_results = {
@@ -400,7 +442,7 @@ def run_desal(
                 print("Fresh water needed (m^3/hr): ", desal_capacity_m3_per_hour)
 
         elif design_scenario["electrolyzer_location"] == "turbine":
-            nturbines = plant_config["plant"]["num_turbines"]
+            nturbines = plant_config["technologies"]["wind"]["num_turbines"]
 
             # size for per-turbine desal #TODO consider using individual power generation time series from each turbine
             in_turb_freshwater_kg_per_hr = freshwater_kg_per_hr / nturbines
diff --git a/greenheart/tools/eco/finance.py b/greenheart/tools/eco/finance.py
index ccac16b74..2264429d7 100644
--- a/greenheart/tools/eco/finance.py
+++ b/greenheart/tools/eco/finance.py
@@ -7,8 +7,167 @@
 from ORBIT import ProjectManager
 import pandas as pd
 
+from typing import Dict, Union, Optional
+
+from attrs import define, Factory, field
+
+from hopp.simulation import HoppInterface
+
+@define
+class WindCostConfig:
+    """
+    Represents the inputs to the wind cost models
+
+    Attributes:
+        design_scenario (Dict[str, str]):
+            Definition of plant subsystem locations (e.g. onshore platform, offshore, none, etc)
+        hopp_config (Dict[str, float]):
+            Configuration parameters for HOPP
+        greenheart_config (Dict[str, float]):
+            Configuration parameters for Greenheart
+        orbit_config (Dict[str, float], optional):
+            Required input structure for ORBIT
+        turbine_config (Dict[str, float], optional):
+            Configuration parameters specific to turbine
+        orbit_hybrid_electrical_export_config (Dict[str, float], optional):
+            Configuration parameters for hybrid electrical export in ORBIT, required if using a different substation size for the hybrid plant than for the wind plant alone
+        weather (Union[list, tuple, numpy.ndarray], optional):
+            Array-like of wind speeds for ORBIT to use in determining installation time and costs
+    """
+
+    design_scenario: Dict[str, str]
+    hopp_config: Dict[str, float]
+    greenheart_config: Dict[str, float]
+    orbit_config: Optional[Dict[str, float]] = field(default={})
+    turbine_config: Optional[Dict[str, float]] = field(default={})
+    orbit_hybrid_electrical_export_config: Optional[Dict[str, float]] = field(
+        default={}
+    )
+    weather: Optional[Union[list, tuple, np.ndarray]] = field(default=None)
+    hopp_interface: Optional[HoppInterface] = field(default=None)
+
+@define
+class WindCostOutputs:
+    """
+    Represents the outputs to the wind cost models.
+
+    Attributes:
+        total_wind_cost_no_export (float):
+            Total wind cost without export system costs
+        total_used_export_system_costs (float):
+            Total used export system costs
+        annual_operating_cost_wind (float):
+            Annual operating cost for wind
+        installation_time (float, optional):
+            Estimated installation time in months (default: 0.0)
+        orbit_project (dict, optional):
+            Details of the ORBIT project (default: None)
+    """
+
+    total_wind_cost_no_export: float
+    annual_operating_cost_wind: float
+    installation_time: float = field(default=0.0)
+    total_used_export_system_costs: Optional[float] = field(default=0.0)
+    orbit_project: Optional[Union[dict, ProjectManager]] = field(default=None)
+
+
+def run_wind_cost_model(
+    wind_cost_inputs: WindCostConfig, verbose=False
+) -> WindCostOutputs:
+
+    if wind_cost_inputs.design_scenario["wind_location"] == "offshore":
+
+        # if per kw
+        project, orbit_hybrid_electrical_export_project = run_orbit(
+            wind_cost_inputs.orbit_config,
+            verbose=verbose,
+            weather=wind_cost_inputs.weather,
+            orbit_hybrid_electrical_export_config=wind_cost_inputs.orbit_hybrid_electrical_export_config,
+        )
+
+        total_wind_cost_no_export, total_used_export_system_costs = (
+            breakout_export_costs_from_orbit_results(
+                project,
+                wind_cost_inputs.greenheart_config,
+                wind_cost_inputs.design_scenario,
+            )
+        )
+
+        if orbit_hybrid_electrical_export_project is not None:
+            _, total_used_export_system_costs = (
+                breakout_export_costs_from_orbit_results(
+                    orbit_hybrid_electrical_export_project,
+                    wind_cost_inputs.greenheart_config,
+                    wind_cost_inputs.design_scenario,
+                )
+            )
+
+        # WIND ONLY Total O&M expenses including fixed, variable, and capacity-based, $/year
+        # use values from hybrid substation if a hybrid plant
+        if orbit_hybrid_electrical_export_project is None:
+
+            annual_operating_cost_wind = (
+                max(project.monthly_opex.values()) * 12
+            )  # np.average(hopp_results["hybrid_plant"].wind.om_total_expense)
+
+        else:
+
+            annual_operating_cost_wind = (
+                max(orbit_hybrid_electrical_export_project.monthly_opex.values()) * 12
+            )
+
+        if ("installation_time" in wind_cost_inputs.greenheart_config["project_parameters"]):
+            installation_time = (
+                wind_cost_inputs.greenheart_config["project_parameters"]["installation_time"]
+            )
+        else:
+            installation_time = (project.installation_time / (365 * 24)) * (12.0 / 1.0)
+
+        # if total amount
+        # TODO
+        return WindCostOutputs(
+            total_wind_cost_no_export=total_wind_cost_no_export,
+            total_used_export_system_costs=total_used_export_system_costs,
+            annual_operating_cost_wind=annual_operating_cost_wind,
+            installation_time=installation_time,
+            orbit_project=project,
+        )
+    elif wind_cost_inputs.design_scenario["wind_location"] == "onshore":
+        total_wind_cost_no_export = (
+            wind_cost_inputs.hopp_config["config"]["cost_info"][
+                "wind_installed_cost_mw"
+            ]
+            * wind_cost_inputs.hopp_config["technologies"]["wind"]["num_turbines"]
+            * wind_cost_inputs.turbine_config["turbine_rating"]
+        )
+
+        annual_operating_cost_wind = (
+            wind_cost_inputs.hopp_interface.system.wind.om_total_expense[0]
+        )
+
+        if ("installation_time" in wind_cost_inputs.greenheart_config["project_parameters"]):
+            installation_time = (
+                wind_cost_inputs.greenheart_config["project_parameters"]["installation_time"]
+            )
+        else:
+            installation_time = 0
+
+        return WindCostOutputs(
+            total_wind_cost_no_export=total_wind_cost_no_export,
+            annual_operating_cost_wind=annual_operating_cost_wind,
+            installation_time=installation_time,
+        )
+    else:
+        raise ValueError(
+            "Wind design location must either be 'onshore' or 'offshore', but currently "
+            f"'wind_location' is set to {wind_cost_inputs.design_scenario['wind_location']}."
+        )
+
+
 # Function to run orbit from provided inputs - this is just for wind costs
-def run_orbit(orbit_config, verbose=False, weather=None, orbit_hybrid_electrical_export_config={}):
+def run_orbit(
+    orbit_config, verbose=False, weather=None, orbit_hybrid_electrical_export_config={}
+):
     # set up ORBIT
     project = ProjectManager(orbit_config, weather=weather)
 
@@ -19,8 +178,12 @@ def run_orbit(orbit_config, verbose=False, weather=None, orbit_hybrid_electrical
     if orbit_hybrid_electrical_export_config == {}:
         hybrid_substation_project = None
     else:
-        hybrid_substation_project = ProjectManager(orbit_hybrid_electrical_export_config, weather=weather)
-        hybrid_substation_project.run(availability=orbit_config["installation_availability"])
+        hybrid_substation_project = ProjectManager(
+            orbit_hybrid_electrical_export_config, weather=weather
+        )
+        hybrid_substation_project.run(
+            availability=orbit_config["installation_availability"]
+        )
 
     # print results if desired
     if verbose:
@@ -48,38 +211,45 @@ def run_orbit(orbit_config, verbose=False, weather=None, orbit_hybrid_electrical
 
 def adjust_orbit_costs(orbit_project, greenheart_config):
 
-    if ("expected_plant_cost" in greenheart_config["finance_parameters"]["wind"]) and (greenheart_config["finance_parameters"]["wind"]["expected_plant_cost"] != 'none'):
-        wind_capex_multiplier = (greenheart_config["finance_parameters"]["wind"]["expected_plant_cost"]*1E9)/orbit_project.total_capex
+    if ("expected_plant_cost" in greenheart_config["finance_parameters"]["wind"]) and (
+        greenheart_config["finance_parameters"]["wind"]["expected_plant_cost"] != "none"
+    ):
+        wind_capex_multiplier = (
+            greenheart_config["finance_parameters"]["wind"]["expected_plant_cost"] * 1e9
+        ) / orbit_project.total_capex
     else:
         wind_capex_multiplier = 1.0
 
-    wind_total_capex = orbit_project.total_capex*wind_capex_multiplier
+    wind_total_capex = orbit_project.total_capex * wind_capex_multiplier
     wind_capex_breakdown = orbit_project.capex_breakdown
     for key in wind_capex_breakdown.keys():
         wind_capex_breakdown[key] *= wind_capex_multiplier
 
     return wind_total_capex, wind_capex_breakdown, wind_capex_multiplier
 
-def breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, design_scenario):
+
+def breakout_export_costs_from_orbit_results(
+    orbit_project, greenheart_config, design_scenario
+):
     # adjust wind capex to meet expectations
-    wind_total_capex, wind_capex_breakdown, wind_capex_multiplier = adjust_orbit_costs(orbit_project=orbit_project, greenheart_config=greenheart_config)
-    
+    wind_total_capex, wind_capex_breakdown, wind_capex_multiplier = adjust_orbit_costs(
+        orbit_project=orbit_project, greenheart_config=greenheart_config
+    )
+
     # onshore substation cost is not included in ORBIT costs by default, so we have to add it separately
     total_wind_installed_costs_with_export = wind_total_capex
 
     # breakout export system costs
     array_cable_equipment_cost = wind_capex_breakdown["Array System"]
-    array_cable_installation_cost = wind_capex_breakdown[
-        "Array System Installation"
-    ]
+    array_cable_installation_cost = wind_capex_breakdown["Array System Installation"]
     total_array_cable_system_capex = (
         array_cable_equipment_cost + array_cable_installation_cost
     )
 
-    export_cable_equipment_cost = wind_capex_breakdown["Export System"] # this should include the onshore substation
-    export_cable_installation_cost = wind_capex_breakdown[
-        "Export System Installation"
-    ]
+    export_cable_equipment_cost = wind_capex_breakdown[
+        "Export System"
+    ]  # this should include the onshore substation
+    export_cable_installation_cost = wind_capex_breakdown["Export System Installation"]
     substation_equipment_cost = wind_capex_breakdown["Offshore Substation"]
     substation_installation_cost = wind_capex_breakdown[
         "Offshore Substation Installation"
@@ -88,7 +258,9 @@ def breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, d
         export_cable_equipment_cost + export_cable_installation_cost
     )
 
-    total_offshore_substation_capex = substation_equipment_cost + substation_installation_cost
+    total_offshore_substation_capex = (
+        substation_equipment_cost + substation_installation_cost
+    )
 
     total_electrical_export_system_cost = (
         total_array_cable_system_capex
@@ -123,10 +295,9 @@ def breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, d
             total_export_cable_system_capex  # TODO check assumptions here
         )
     elif (
-        (design_scenario["electrolyzer_location"] == "platform" or
-         design_scenario["electrolyzer_location"] == "turbine")
-        and design_scenario["h2_storage_location"] == "onshore"
-    ):
+        design_scenario["electrolyzer_location"] == "platform"
+        or design_scenario["electrolyzer_location"] == "turbine"
+    ) and design_scenario["h2_storage_location"] == "onshore":
         unused_export_system_cost = (
             total_export_cable_system_capex  # TODO check assumptions here
         )
@@ -143,10 +314,10 @@ def breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, d
 
     return total_wind_cost_no_export, total_used_export_system_costs
 
+
 def run_capex(
     hopp_results,
-    orbit_project,
-    orbit_hybrid_electrical_export_project,
+    wind_cost_results,
     electrolyzer_cost_results,
     h2_pipe_array_results,
     h2_transport_compressor_results,
@@ -154,39 +325,44 @@ def run_capex(
     h2_storage_results,
     hopp_config,
     greenheart_config,
-    orbit_config,
     design_scenario,
     desal_results,
     platform_results,
     verbose=False,
 ):
-    
-    total_wind_cost_no_export, total_used_export_system_costs = breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, design_scenario)
-    
-    if orbit_hybrid_electrical_export_project is not None:
-        _, total_used_export_system_costs = breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, design_scenario)
+
+    # total_wind_cost_no_export, total_used_export_system_costs = breakout_export_costs_from_orbit_results(orbit_project, greenheart_config, design_scenario)
+
+    # if orbit_hybrid_electrical_export_project is not None:
+    #     _, total_used_export_system_costs = breakout_export_costs_from_orbit_results(orbit_hybrid_electrical_export_project, greenheart_config, design_scenario)
 
     # wave capex
     if hopp_config["site"]["wave"]:
         cost_dict = hopp_results["hybrid_plant"].wave.mhk_costs.cost_outputs
 
-        wcapex = cost_dict['structural_assembly_cost_modeled']+\
-            cost_dict['power_takeoff_system_cost_modeled']+\
-            cost_dict['mooring_found_substruc_cost_modeled']
-        wbos = cost_dict['development_cost_modeled']+\
-            cost_dict['eng_and_mgmt_cost_modeled']+\
-            cost_dict['plant_commissioning_cost_modeled']+\
-            cost_dict['site_access_port_staging_cost_modeled']+\
-            cost_dict['assembly_and_install_cost_modeled']+\
-            cost_dict['other_infrastructure_cost_modeled']
-        welec_infrastruc_costs = cost_dict['array_cable_system_cost_modeled']+\
-            cost_dict['export_cable_system_cost_modeled']+\
-            cost_dict['other_elec_infra_cost_modeled'] # +\
-            # cost_dict['onshore_substation_cost_modeled']+\
-            # cost_dict['offshore_substation_cost_modeled']
+        wcapex = (
+            cost_dict["structural_assembly_cost_modeled"]
+            + cost_dict["power_takeoff_system_cost_modeled"]
+            + cost_dict["mooring_found_substruc_cost_modeled"]
+        )
+        wbos = (
+            cost_dict["development_cost_modeled"]
+            + cost_dict["eng_and_mgmt_cost_modeled"]
+            + cost_dict["plant_commissioning_cost_modeled"]
+            + cost_dict["site_access_port_staging_cost_modeled"]
+            + cost_dict["assembly_and_install_cost_modeled"]
+            + cost_dict["other_infrastructure_cost_modeled"]
+        )
+        welec_infrastruc_costs = (
+            cost_dict["array_cable_system_cost_modeled"]
+            + cost_dict["export_cable_system_cost_modeled"]
+            + cost_dict["other_elec_infra_cost_modeled"]
+        )  # +\
+        # cost_dict['onshore_substation_cost_modeled']+\
+        # cost_dict['offshore_substation_cost_modeled']
         # financial = cost_dict['project_contingency']+\
-            # cost_dict['insurance_during_construction']+\
-            # cost_dict['reserve_accounts']
+        # cost_dict['insurance_during_construction']+\
+        # cost_dict['reserve_accounts']
         wave_capex = wcapex + wbos + welec_infrastruc_costs
     else:
         wave_capex = 0.0
@@ -254,16 +430,19 @@ def run_capex(
     ):  # lined rock cavern storage model includes compression
         h2_storage_capex = h2_storage_results["storage_capex"]
     else:
-        raise NotImplementedError("the storage type you have indicated (%s) has not been implemented." % greenheart_config["h2_storage"]["type"])
+        raise NotImplementedError(
+            "the storage type you have indicated (%s) has not been implemented."
+            % greenheart_config["h2_storage"]["type"]
+        )
 
     # store capex component breakdown
     capex_breakdown = {
-        "wind": total_wind_cost_no_export,
+        "wind": wind_cost_results.total_wind_cost_no_export,
         "wave": wave_capex,
         "solar": solar_capex,
         "battery": battery_capex,
         "platform": platform_costs,
-        "electrical_export_system": total_used_export_system_costs,
+        "electrical_export_system": wind_cost_results.total_used_export_system_costs,
         "desal": desal_capex,
         "electrolyzer": electrolyzer_total_capital_cost,
         "h2_pipe_array": h2_pipe_array_results["capex"],
@@ -286,7 +465,7 @@ def run_capex(
         else:
             cost_year = greenheart_config["finance_parameters"]["discount_years"][key]
 
-        periods = orbit_config["cost_year"] - cost_year
+        periods = greenheart_config["project_parameters"]["cost_year"] - cost_year
 
         capex_breakdown[key] = -npf.fv(
             greenheart_config["finance_parameters"]["general_inflation"],
@@ -312,10 +491,10 @@ def run_capex(
 
     return total_system_installed_cost, capex_breakdown
 
+
 def run_opex(
     hopp_results,
-    orbit_project,
-    orbit_hybrid_electrical_export_project,
+    wind_cost_results,
     electrolyzer_cost_results,
     h2_pipe_array_results,
     h2_transport_compressor_results,
@@ -323,7 +502,6 @@ def run_opex(
     h2_storage_results,
     hopp_config,
     greenheart_config,
-    orbit_config,
     desal_results,
     platform_results,
     verbose=False,
@@ -331,17 +509,9 @@ def run_opex(
 ):
     # WIND ONLY Total O&M expenses including fixed, variable, and capacity-based, $/year
     # use values from hybrid substation if a hybrid plant
-    if orbit_hybrid_electrical_export_project is None:
-        
-        annual_operating_cost_wind = (
-            max(orbit_project.monthly_opex.values()) * 12
-        )  # np.average(hopp_results["hybrid_plant"].wind.om_total_expense)
+    # if orbit_hybrid_electrical_export_project is None:
+
 
-    else:
-        
-        annual_operating_cost_wind = (
-            max(orbit_hybrid_electrical_export_project.monthly_opex.values()) * 12
-        )
 
     # wave opex
     if hopp_config["site"]["wave"]:
@@ -357,7 +527,7 @@ def run_opex(
             raise(RuntimeWarning(f"Solar OPEX returned as {solar_opex}"))
     else:
         solar_opex = 0.0
-        
+
     # battery opex
     if "battery" in hopp_config["technologies"].keys():
         battery_opex = hopp_results["hybrid_plant"].battery.om_fixed + np.sum(hopp_results["hybrid_plant"].battery.om_variable)
@@ -365,7 +535,6 @@ def run_opex(
             raise(RuntimeWarning(f"Battery OPEX returned as {battery_opex}"))
     else:
         battery_opex = 0.0
-    
 
     # H2 OPEX
     platform_operating_costs = platform_results["opex"]  # TODO update this
@@ -390,7 +559,7 @@ def run_opex(
 
     # store opex component breakdown
     opex_breakdown_annual = {
-        "wind_and_electrical": annual_operating_cost_wind,
+        "wind_and_electrical": wind_cost_results.annual_operating_cost_wind,
         "platform": platform_operating_costs,
         #   "electrical_export_system": total_export_om_cost,
         "wave": wave_opex,
@@ -413,7 +582,7 @@ def run_opex(
         else:
             cost_year = greenheart_config["finance_parameters"]["discount_years"][key]
 
-        periods = orbit_config["cost_year"] - cost_year
+        periods = greenheart_config["project_parameters"]["cost_year"] - cost_year
         opex_breakdown_annual[key] = -npf.fv(
             greenheart_config["finance_parameters"]["general_inflation"],
             periods,
@@ -440,8 +609,7 @@ def run_opex(
 
 def run_profast_lcoe(
     greenheart_config,
-    orbit_config,
-    orbit_project,
+    wind_cost_results,
     capex_breakdown,
     opex_breakdown,
     hopp_results,
@@ -472,19 +640,14 @@ def run_profast_lcoe(
         },
     )
     pf.set_params(
-        "capacity", np.sum(hopp_results["combined_hybrid_power_production_hopp"]) / 365.0
+        "capacity",
+        np.sum(hopp_results["combined_hybrid_power_production_hopp"]) / 365.0,
     )  # kWh/day
     pf.set_params("maintenance", {"value": 0, "escalation": gen_inflation})
-    pf.set_params("analysis start year", orbit_config["atb_year"] + 1)
-    pf.set_params(
-        "operating life", orbit_config["project_parameters"]["project_lifetime"]
-    )
-    pf.set_params(
-        "installation months",
-        (orbit_project.installation_time / (365 * 24)) * (12.0 / 1.0),
-    )
-    pf.set_params(
-        "installation cost",
+    pf.set_params("analysis start year", greenheart_config["project_parameters"]["atb_year"] + 1)
+    pf.set_params("operating life", greenheart_config["project_parameters"]["project_lifetime"])
+    pf.set_params("installation months", wind_cost_results.installation_time)
+    pf.set_params("installation cost",
         {
             "value": 0,
             "depr type": "Straight line",
@@ -497,7 +660,8 @@ def run_profast_lcoe(
         pf.set_params(
             "end of proj sale non depr assets",
             land_cost
-            * (1 + gen_inflation) ** orbit_config["project_parameters"]["project_lifetime"],
+            * (1 + gen_inflation)
+            ** greenheart_config["project_parameters"]["project_lifetime"],
         )
     pf.set_params("demand rampup", 0)
     pf.set_params("long term utilization", 1)
@@ -512,7 +676,9 @@ def run_profast_lcoe(
     )
     pf.set_params(
         "admin expense",
-        greenheart_config["finance_parameters"]["administrative_expense_percent_of_sales"],
+        greenheart_config["finance_parameters"][
+            "administrative_expense_percent_of_sales"
+        ],
     )
     pf.set_params(
         "total income tax rate",
@@ -541,7 +707,8 @@ def run_profast_lcoe(
         "loan period if used", greenheart_config["finance_parameters"]["loan_period"]
     )
     pf.set_params(
-        "debt interest rate", greenheart_config["finance_parameters"]["debt_interest_rate"]
+        "debt interest rate",
+        greenheart_config["finance_parameters"]["debt_interest_rate"],
     )
     pf.set_params(
         "cash onhand", greenheart_config["finance_parameters"]["cash_onhand_months"]
@@ -564,7 +731,7 @@ def run_profast_lcoe(
             depr_period=greenheart_config["finance_parameters"]["depreciation_period"],
             refurb=[0],
         )
-        
+
     if "solar" in capex_breakdown.keys():
         pf.add_capital_item(
             name="Solar System",
@@ -583,9 +750,9 @@ def run_profast_lcoe(
             refurb=[0],
         )
 
-    if (design_scenario["transportation"] == "hvdc+pipeline" or not 
-        (design_scenario["electrolyzer_location"] == "turbine"
-        and design_scenario["h2_storage_location"] == "turbine")
+    if design_scenario["transportation"] == "hvdc+pipeline" or not (
+        design_scenario["electrolyzer_location"] == "turbine"
+        and design_scenario["h2_storage_location"] == "turbine"
     ):
         pf.add_capital_item(
             name="Electrical Export system",
@@ -630,25 +797,26 @@ def run_profast_lcoe(
             cost=opex_breakdown["battery"],
             escalation=gen_inflation,
         )
-    
 
     # ------------------------------------- add incentives -----------------------------------
     """ Note: ptc units must be given to ProFAST in terms of dollars per unit of the primary commodity being produced
         Note: full tech-nutral (wind) tax credits are no longer available if constructions starts after Jan. 1 2034 (Jan 1. 2033 for h2 ptc)"""
 
     # catch incentive option and add relevant incentives
-    incentive_dict = greenheart_config["policy_parameters"]["option%s" % (incentive_option)]
+    incentive_dict = greenheart_config["policy_parameters"][
+        "option%s" % (incentive_option)
+    ]
     # add electricity_ptc ($/kW)
     # adjust from 1992 dollars to start year
     wind_ptc_in_dollars_per_kw = -npf.fv(
         gen_inflation,
-        orbit_config["atb_year"]
-        + round((orbit_project.installation_time / (365 * 24)))
+        greenheart_config["project_parameters"]["atb_year"]
+        + round((wind_cost_results.installation_time / 12))
         - 1992,
         0,
         incentive_dict["electricity_ptc"],
     )  # given in 1992 dollars but adjust for inflation
-    
+
     pf.add_incentive(
         name="Electricity PTC",
         value=wind_ptc_in_dollars_per_kw,
@@ -704,9 +872,8 @@ def run_profast_lcoe(
 
 
 def run_profast_grid_only(
-    greenheart_config, 
-    orbit_config,
-    orbit_project,
+    greenheart_config,
+    wind_cost_results,
     electrolyzer_physics_results,
     capex_breakdown,
     opex_breakdown,
@@ -743,11 +910,12 @@ def run_profast_grid_only(
         electrolyzer_physics_results["H2_Results"]["hydrogen_annual_output"] / 365.0,
     )  # kg/day
     pf.set_params("maintenance", {"value": 0, "escalation": gen_inflation})
-    pf.set_params("analysis start year", orbit_config["atb_year"] + 1)
     pf.set_params(
-        "operating life", orbit_config["project_parameters"]["project_lifetime"]
+        "analysis start year", greenheart_config["project_parameters"]["atb_year"] + 1
+    )
+    pf.set_params(
+        "operating life", greenheart_config["project_parameters"]["project_lifetime"]
     )
-    # pf.set_params('installation months', (orbit_project.installation_time/(365*24))*(12.0/1.0))
     pf.set_params(
         "installation cost",
         {
@@ -762,12 +930,15 @@ def run_profast_grid_only(
         pf.set_params(
             "end of proj sale non depr assets",
             land_cost
-            * (1 + gen_inflation) ** orbit_config["project_parameters"]["project_lifetime"],
+            * (1 + gen_inflation)
+            ** greenheart_config["project_parameters"]["project_lifetime"],
         )
     pf.set_params("demand rampup", 0)
     pf.set_params("long term utilization", 1)
     pf.set_params("credit card fees", 0)
-    pf.set_params("sales tax", greenheart_config["finance_parameters"]["sales_tax_rate"])
+    pf.set_params(
+        "sales tax", greenheart_config["finance_parameters"]["sales_tax_rate"]
+    )
     pf.set_params("license and permit", {"value": 00, "escalation": gen_inflation})
     pf.set_params("rent", {"value": 0, "escalation": gen_inflation})
     pf.set_params(
@@ -777,7 +948,9 @@ def run_profast_grid_only(
     )
     pf.set_params(
         "admin expense",
-        greenheart_config["finance_parameters"]["administrative_expense_percent_of_sales"],
+        greenheart_config["finance_parameters"][
+            "administrative_expense_percent_of_sales"
+        ],
     )
     pf.set_params(
         "total income tax rate",
@@ -806,7 +979,8 @@ def run_profast_grid_only(
         "loan period if used", greenheart_config["finance_parameters"]["loan_period"]
     )
     pf.set_params(
-        "debt interest rate", greenheart_config["finance_parameters"]["debt_interest_rate"]
+        "debt interest rate",
+        greenheart_config["finance_parameters"]["debt_interest_rate"],
     )
     pf.set_params(
         "cash onhand", greenheart_config["finance_parameters"]["cash_onhand_months"]
@@ -823,17 +997,17 @@ def run_profast_grid_only(
     # )
 
     electrolyzer_refurbishment_schedule = np.zeros(
-        orbit_config["project_parameters"]["project_lifetime"]
+        greenheart_config["project_parameters"]["project_lifetime"]
     )
     refurb_period = round(
         greenheart_config["electrolyzer"]["time_between_replacement"] / (24 * 365)
     )
     electrolyzer_refurbishment_schedule[
-        refurb_period : orbit_config["project_parameters"][
+        refurb_period : greenheart_config["project_parameters"][
             "project_lifetime"
         ] : refurb_period
     ] = greenheart_config["electrolyzer"]["replacement_cost_percent"]
-    
+
     pf.add_capital_item(
         name="Electrolysis System",
         cost=capex_breakdown["electrolyzer"],
@@ -888,7 +1062,11 @@ def run_profast_grid_only(
 
     # if greenheart_config["project_parameters"]["grid_connection"]:
 
-    energy_purchase = 365*24*greenheart_config["electrolyzer"]["rating"] * 1e3 + total_accessory_power_renewable_kw + total_accessory_power_grid_kw
+    energy_purchase = (
+        365 * 24 * greenheart_config["electrolyzer"]["rating"] * 1e3
+        + total_accessory_power_renewable_kw
+        + total_accessory_power_grid_kw
+    )
 
     pf.add_fixed_cost(
         name="Electricity from grid",
@@ -926,7 +1104,8 @@ def run_profast_grid_only(
                 os.mkdir(savepath)
 
         pf.plot_capital_expenses(
-            fileout="figures/capex/capital_expense_grid_only_%i.pdf" % (design_scenario["id"]),
+            fileout="figures/capex/capital_expense_grid_only_%i.pdf"
+            % (design_scenario["id"]),
             show_plot=show_plots,
         )
         pf.plot_cashflow(
@@ -935,7 +1114,9 @@ def run_profast_grid_only(
             show_plot=show_plots,
         )
 
-        pd.DataFrame.from_dict(data=pf.cash_flow_out, orient='index').to_csv("data/cash_flow_grid_only_%i.csv" % (design_scenario["id"]))
+        pd.DataFrame.from_dict(data=pf.cash_flow_out, orient="index").to_csv(
+            "data/cash_flow_grid_only_%i.csv" % (design_scenario["id"])
+        )
 
         pf.plot_costs(
             "figures/lcoh_breakdown/lcoh_grid_only_%i" % (design_scenario["id"]),
@@ -946,8 +1127,7 @@ def run_profast_grid_only(
 
 def run_profast_full_plant_model(
     greenheart_config,
-    orbit_config,
-    orbit_project,
+    wind_cost_results,
     electrolyzer_physics_results,
     capex_breakdown,
     opex_breakdown,
@@ -985,14 +1165,18 @@ def run_profast_full_plant_model(
         electrolyzer_physics_results["H2_Results"]["hydrogen_annual_output"] / 365.0,
     )  # kg/day
     pf.set_params("maintenance", {"value": 0, "escalation": gen_inflation})
-    pf.set_params("analysis start year", orbit_config["atb_year"] + 1)
     pf.set_params(
-        "operating life", orbit_config["project_parameters"]["project_lifetime"]
+        "analysis start year",
+        greenheart_config["project_parameters"]["atb_year"]
+        + 1,  # Add financial analysis start year
+    )
+    pf.set_params(
+        "operating life", greenheart_config["project_parameters"]["project_lifetime"]
     )
     pf.set_params(
         "installation months",
-        (orbit_project.installation_time / (365 * 24)) * (12.0 / 1.0),
-    )  # convert from hours to months
+        wind_cost_results.installation_time, # Add installation time to yaml default=0
+    )
     pf.set_params(
         "installation cost",
         {
@@ -1007,12 +1191,15 @@ def run_profast_full_plant_model(
         pf.set_params(
             "end of proj sale non depr assets",
             land_cost
-            * (1 + gen_inflation) ** orbit_config["project_parameters"]["project_lifetime"],
+            * (1 + gen_inflation)
+            ** greenheart_config["project_parameters"]["project_lifetime"],
         )
     pf.set_params("demand rampup", 0)
     pf.set_params("long term utilization", 1)  # TODO should use utilization
     pf.set_params("credit card fees", 0)
-    pf.set_params("sales tax", greenheart_config["finance_parameters"]["sales_tax_rate"])
+    pf.set_params(
+        "sales tax", greenheart_config["finance_parameters"]["sales_tax_rate"]
+    )
     pf.set_params("license and permit", {"value": 00, "escalation": gen_inflation})
     pf.set_params("rent", {"value": 0, "escalation": gen_inflation})
     # TODO how to handle property tax and insurance for fully offshore?
@@ -1023,7 +1210,9 @@ def run_profast_full_plant_model(
     )
     pf.set_params(
         "admin expense",
-        greenheart_config["finance_parameters"]["administrative_expense_percent_of_sales"],
+        greenheart_config["finance_parameters"][
+            "administrative_expense_percent_of_sales"
+        ],
     )
     pf.set_params(
         "total income tax rate",
@@ -1052,7 +1241,8 @@ def run_profast_full_plant_model(
         "loan period if used", greenheart_config["finance_parameters"]["loan_period"]
     )
     pf.set_params(
-        "debt interest rate", greenheart_config["finance_parameters"]["debt_interest_rate"]
+        "debt interest rate",
+        greenheart_config["finance_parameters"]["debt_interest_rate"],
     )
     pf.set_params(
         "cash onhand", greenheart_config["finance_parameters"]["cash_onhand_months"]
@@ -1092,7 +1282,7 @@ def run_profast_full_plant_model(
             depr_period=greenheart_config["finance_parameters"]["depreciation_period"],
             refurb=[0],
         )
-        
+
     if "platform" in capex_breakdown.keys() and capex_breakdown["platform"] > 0:
         pf.add_capital_item(
             name="Equipment Platform",
@@ -1157,13 +1347,13 @@ def run_profast_full_plant_model(
         # TODO assess if this makes sense (electrical export O&M included in wind O&M)
 
     electrolyzer_refurbishment_schedule = np.zeros(
-        orbit_config["project_parameters"]["project_lifetime"]
+        greenheart_config["project_parameters"]["project_lifetime"]
     )
     refurb_period = round(
         greenheart_config["electrolyzer"]["time_between_replacement"] / (24 * 365)
     )
     electrolyzer_refurbishment_schedule[
-        refurb_period : orbit_config["project_parameters"][
+        refurb_period : greenheart_config["project_parameters"][
             "project_lifetime"
         ] : refurb_period
     ] = greenheart_config["electrolyzer"]["replacement_cost_percent"]
@@ -1204,13 +1394,15 @@ def run_profast_full_plant_model(
         )
 
     if (
-        design_scenario["h2_storage_location"] == "onshore"
-        and design_scenario["electrolyzer_location"] != "onshore"
-    ) or (
-        design_scenario["h2_storage_location"] != "onshore"
-        and design_scenario["electrolyzer_location"] == "onshore"
-    ) or (
-        design_scenario["transportation"] == "hvdc+pipeline"
+        (
+            design_scenario["h2_storage_location"] == "onshore"
+            and design_scenario["electrolyzer_location"] != "onshore"
+        )
+        or (
+            design_scenario["h2_storage_location"] != "onshore"
+            and design_scenario["electrolyzer_location"] == "onshore"
+        )
+        or (design_scenario["transportation"] == "hvdc+pipeline")
     ):
         pf.add_capital_item(
             name="H2 Transport Compressor System",
@@ -1294,9 +1486,12 @@ def run_profast_full_plant_model(
             escalation=gen_inflation,
         )
 
-    if greenheart_config["project_parameters"]["grid_connection"] or total_accessory_power_grid_kw > 0:
+    if (
+        greenheart_config["project_parameters"]["grid_connection"]
+        or total_accessory_power_grid_kw > 0
+    ):
 
-        energy_purchase = total_accessory_power_grid_kw*365*24
+        energy_purchase = total_accessory_power_grid_kw * 365 * 24
 
         if greenheart_config["project_parameters"]["grid_connection"]:
             annual_energy_shortfall = np.sum(hopp_results["energy_shortfall_hopp"])
@@ -1315,7 +1510,9 @@ def run_profast_full_plant_model(
         Note: full tech-nutral (wind) tax credits are no longer available if constructions starts after Jan. 1 2034 (Jan 1. 2033 for h2 ptc)"""
 
     # catch incentive option and add relevant incentives
-    incentive_dict = greenheart_config["policy_parameters"]["option%s" % (incentive_option)]
+    incentive_dict = greenheart_config["policy_parameters"][
+        "option%s" % (incentive_option)
+    ]
 
     # add wind_itc (% of wind capex)
     electricity_itc_value_percent_wind_capex = incentive_dict["electricity_itc"]
@@ -1327,7 +1524,9 @@ def run_profast_full_plant_model(
         {
             "value": electricity_itc_value_dollars,
             "depr type": greenheart_config["finance_parameters"]["depreciation_method"],
-            "depr period": greenheart_config["finance_parameters"]["depreciation_period"],
+            "depr period": greenheart_config["finance_parameters"][
+                "depreciation_period"
+            ],
             "depreciable": True,
         },
     )
@@ -1336,8 +1535,8 @@ def run_profast_full_plant_model(
     # adjust from 1992 dollars to start year
     electricity_ptc_in_dollars_per_kw = -npf.fv(
         gen_inflation,
-        orbit_config["atb_year"]
-        + round((orbit_project.installation_time / (365 * 24)))
+        greenheart_config["project_parameters"]["atb_year"]
+        + round((wind_cost_results.installation_time / 12))
         - 1992,
         0,
         incentive_dict["electricity_ptc"],
@@ -1346,7 +1545,9 @@ def run_profast_full_plant_model(
         sum(hopp_results["combined_hybrid_power_production_hopp"])
         / electrolyzer_physics_results["H2_Results"]["hydrogen_annual_output"]
     )
-    electricity_ptc_in_dollars_per_kg_h2 = electricity_ptc_in_dollars_per_kw * kw_per_kg_h2
+    electricity_ptc_in_dollars_per_kg_h2 = (
+        electricity_ptc_in_dollars_per_kw * kw_per_kg_h2
+    )
     pf.add_incentive(
         name="Electricity PTC",
         value=electricity_ptc_in_dollars_per_kg_h2,
@@ -1358,8 +1559,8 @@ def run_profast_full_plant_model(
     # add h2_ptc ($/kg)
     h2_ptc_inflation_adjusted = -npf.fv(
         gen_inflation,
-        orbit_config["atb_year"]
-        + round((orbit_project.installation_time / (365 * 24)))
+        greenheart_config["project_parameters"]["atb_year"]
+        + round((wind_cost_results.installation_time / 12))
         - 2022,
         0,
         incentive_dict["h2_ptc"],
@@ -1436,7 +1637,9 @@ def run_profast_full_plant_model(
             show_plot=show_plots,
         )
 
-        pd.DataFrame.from_dict(data=pf.cash_flow_out).to_csv("data/cash_flow_%i.csv" % (design_scenario["id"]))
+        pd.DataFrame.from_dict(data=pf.cash_flow_out).to_csv(
+            "data/cash_flow_%i.csv" % (design_scenario["id"])
+        )
 
         pf.plot_costs(
             "figures/lcoh_breakdown/lcoh_%i" % (design_scenario["id"]),
diff --git a/greenheart/tools/eco/hopp_mgmt.py b/greenheart/tools/eco/hopp_mgmt.py
index 99d026c6a..d3ddc4a15 100644
--- a/greenheart/tools/eco/hopp_mgmt.py
+++ b/greenheart/tools/eco/hopp_mgmt.py
@@ -1,34 +1,45 @@
-import copy 
+import copy
 import numpy as np
 import matplotlib.pyplot as plt
 import os
 
+
 from hopp.simulation.technologies.sites import SiteInfo
 from hopp.simulation.technologies.sites import flatirons_site as sample_site
 from hopp.simulation.hopp_interface import HoppInterface
+from hopp.simulation.technologies.layout.wind_layout_tools import create_grid
+
 
 # Function to set up the HOPP model
 def setup_hopp(
-    hopp_config, 
+    hopp_config,
     greenheart_config,
     orbit_config,
     turbine_config,
-    orbit_project,
     floris_config,
+    design_scenario,
+    wind_cost_results=None,
     show_plots=False,
     save_plots=False,
 ):
-    hopp_site = SiteInfo(**hopp_config["site"], desired_schedule=[greenheart_config["electrolyzer"]["rating"]]*8760)
+    hopp_site = SiteInfo(
+        **hopp_config["site"],
+        desired_schedule=[greenheart_config["electrolyzer"]["rating"]] * 8760
+    )
 
     # adjust mean wind speed if desired
-    wind_data = hopp_site.wind_resource._data['data']
+    wind_data = hopp_site.wind_resource._data["data"]
     wind_speed = [W[2] for W in wind_data]
     if greenheart_config["site"]["mean_windspeed"]:
         if np.average(wind_speed) != greenheart_config["site"]["mean_windspeed"]:
-            wind_speed += greenheart_config["site"]["mean_windspeed"] - np.average(wind_speed)
+            wind_speed += greenheart_config["site"]["mean_windspeed"] - np.average(
+                wind_speed
+            )
             for i in np.arange(0, len(wind_speed)):
                 # make sure we don't have negative wind speeds after correction
-                hopp_site.wind_resource._data['data'][i][2] = np.maximum(wind_speed[i], 0)
+                hopp_site.wind_resource._data["data"][i][2] = np.maximum(
+                    wind_speed[i], 0
+                )
     else:
         greenheart_config["site"]["mean_windspeed"] = np.average(wind_speed)
 
@@ -36,17 +47,60 @@ def setup_hopp(
     hopp_technologies = {}
     if hopp_config["site"]["wind"]:
         if hopp_config["technologies"]["wind"]["model_name"] == "floris":
-            floris_config["farm"]["layout_x"] = (
-                orbit_project.phases["ArraySystemDesign"].turbines_x.flatten() * 1e3
-            )  # ORBIT gives coordinates in km
-            # ORBIT produces nans and must be removed for FLORIS layout
-            floris_config["farm"]["layout_x"] = floris_config["farm"]["layout_x"][~np.isnan(floris_config["farm"]["layout_x"])]
-            floris_config["farm"]["layout_y"] = (
-                orbit_project.phases["ArraySystemDesign"].turbines_y.flatten() * 1e3
-            )  # ORBIT gives coordinates in km
-            # ORBIT produces nans and must be removed for FLORIS layout
-            floris_config["farm"]["layout_y"] = floris_config["farm"]["layout_y"][~np.isnan(floris_config["farm"]["layout_y"])]
-            # remove things from turbine_config file that can't be used in FLORIS and set the turbine info in the floris config file
+            if design_scenario["wind_location"] == "offshore":
+                floris_config["farm"]["layout_x"] = (
+                    wind_cost_results.orbit_project.phases[
+                        "ArraySystemDesign"
+                    ].turbines_x.flatten()
+                    * 1e3
+                )  # ORBIT gives coordinates in km
+                # ORBIT produces nans and must be removed for FLORIS layout
+                floris_config["farm"]["layout_x"] = floris_config["farm"]["layout_x"][
+                    ~np.isnan(floris_config["farm"]["layout_x"])
+                ]
+                floris_config["farm"]["layout_y"] = (
+                    wind_cost_results.orbit_project.phases[
+                        "ArraySystemDesign"
+                    ].turbines_y.flatten()
+                    * 1e3
+                )  # ORBIT gives coordinates in km
+                # ORBIT produces nans and must be removed for FLORIS layout
+                floris_config["farm"]["layout_y"] = floris_config["farm"]["layout_y"][
+                    ~np.isnan(floris_config["farm"]["layout_y"])
+                ]
+                # remove things from turbine_config file that can't be used in FLORIS and set the turbine info in the floris config file
+
+            if design_scenario["wind_location"] == "onshore":
+                grid_position = create_grid(
+                    site_shape=hopp_site.polygon,
+                    center=hopp_site.polygon.centroid,
+                    grid_angle=greenheart_config["site"]["wind_layout"]["grid_angle"],
+                    intrarow_spacing=(
+                        greenheart_config["site"]["wind_layout"]["row_spacing"]
+                        * turbine_config["rotor_diameter"]
+                    ),
+                    interrow_spacing=(
+                        greenheart_config["site"]["wind_layout"]["turbine_spacing"]
+                        * turbine_config["rotor_diameter"]
+                    ),
+                    row_phase_offset=greenheart_config["site"]["wind_layout"][
+                        "row_phase_offset"
+                    ],
+                    max_sites=hopp_config["technologies"]["wind"]["num_turbines"],
+                )
+                # Extracting xy coordinates
+                xy_coordinates = [(point.x, point.y) for point in grid_position]
+                floris_config["farm"]["layout_x"] = [point.x for point in grid_position]
+                floris_config["farm"]["layout_y"] = [point.y for point in grid_position]
+
+                if (
+                    len(floris_config["farm"]["layout_x"])
+                    < hopp_config["technologies"]["wind"]["num_turbines"]
+                ):
+                    raise Exception(
+                        "size of site is too small, not all turbines were placed."
+                    )
+
             floris_config["farm"]["turbine_type"] = [
                 {
                     x: turbine_config[x]
@@ -69,21 +123,29 @@ def setup_hopp(
 
         elif hopp_config["technologies"]["wind"]["model_name"] == "sam":
             hopp_technologies["wind"] = {
-                    "turbine_rating_kw": turbine_config["turbine_rating"] * 1000,  # convert from MW to kW
-                    "hub_height": turbine_config["hub_height"],
-                    "rotor_diameter": turbine_config["rotor_diameter"],
-                }
+                "turbine_rating_kw": turbine_config["turbine_rating"]
+                * 1000,  # convert from MW to kW
+                "hub_height": turbine_config["hub_height"],
+                "rotor_diameter": turbine_config["rotor_diameter"],
+            }
         else:
-            raise(ValueError("Wind model '%s' not available. Please choose one of ['floris', 'sam']") % (hopp_config["technologies"]["wind"]["model_name"]))
-
-        hopp_technologies["wind"].update({"num_turbines": orbit_config["plant"]["num_turbines"]})
+            raise (
+                ValueError(
+                    "Wind model '%s' not available. Please choose one of ['floris', 'sam']"
+                )
+                % (hopp_config["technologies"]["wind"]["model_name"])
+            )
 
         for key in hopp_technologies["wind"]:
             if key in hopp_config["technologies"]["wind"]:
-                hopp_config["technologies"]["wind"][key] = hopp_technologies["wind"][key]
+                hopp_config["technologies"]["wind"][key] = hopp_technologies["wind"][
+                    key
+                ]
             else:
-                hopp_config["technologies"]["wind"].update(hopp_technologies["wind"][key])
-    
+                hopp_config["technologies"]["wind"].update(
+                    hopp_technologies["wind"][key]
+                )
+
     if show_plots or save_plots:
         # plot wind resource if desired
         print("\nPlotting Wind Resource")
@@ -108,9 +170,10 @@ def setup_hopp(
     ################ return all the inputs for hopp
     return hopp_config, hopp_site
 
+
 # Function to run hopp from provided inputs from setup_hopp()
 def run_hopp(hopp_config, hopp_site, project_lifetime, verbose=False):
-    
+
     hopp_config_internal = copy.deepcopy(hopp_config)
 
     if "wave" in hopp_config_internal["technologies"].keys():
@@ -131,7 +194,8 @@ def run_hopp(hopp_config, hopp_site, project_lifetime, verbose=False):
     hopp_results = {
         "hopp_interface": hi,
         "hybrid_plant": hi.system,
-        "combined_hybrid_power_production_hopp": hi.system.grid._system_model.Outputs.system_pre_interconnect_kwac[0:8759],
+        "combined_hybrid_power_production_hopp": \
+            hi.system.grid._system_model.Outputs.system_pre_interconnect_kwac[0:8759],
         "combined_hybrid_curtailment_hopp": hi.system.grid.generation_curtailed,
         "energy_shortfall_hopp": hi.system.grid.missed_load,
         "annual_energies": hi.system.annual_energies,
@@ -146,4 +210,4 @@ def run_hopp(hopp_config, hopp_site, project_lifetime, verbose=False):
         print("Capacity factors: ", hi.system.capacity_factors)
         print("Real LCOE from HOPP: ", hi.system.lcoe_real)
 
-    return hopp_results
\ No newline at end of file
+    return hopp_results
diff --git a/greenheart/tools/eco/hydrogen_mgmt.py b/greenheart/tools/eco/hydrogen_mgmt.py
index fd7e10ea9..2e431a5fa 100644
--- a/greenheart/tools/eco/hydrogen_mgmt.py
+++ b/greenheart/tools/eco/hydrogen_mgmt.py
@@ -7,20 +7,32 @@
 from ORBIT.phases.design import DesignPhase
 from ORBIT.phases.install import InstallPhase
 
-from greenheart.simulation.technologies.hydrogen.h2_transport.h2_compression import Compressor
-from greenheart.simulation.technologies.hydrogen.h2_storage.pressure_vessel.compressed_gas_storage_model_20221021.Compressed_all import PressureVessel
+from greenheart.simulation.technologies.hydrogen.h2_transport.h2_compression import (
+    Compressor,
+)
+from greenheart.simulation.technologies.hydrogen.h2_storage.pressure_vessel.compressed_gas_storage_model_20221021.Compressed_all import (
+    PressureVessel,
+)
 from greenheart.simulation.technologies.hydrogen.h2_storage.pipe_storage import (
     UndergroundPipeStorage,
 )
 
-from greenheart.simulation.technologies.hydrogen.h2_storage.lined_rock_cavern.lined_rock_cavern import LinedRockCavernStorage
-from greenheart.simulation.technologies.hydrogen.h2_storage.salt_cavern.salt_cavern import SaltCavernStorage
+from greenheart.simulation.technologies.hydrogen.h2_storage.lined_rock_cavern.lined_rock_cavern import (
+    LinedRockCavernStorage,
+)
+from greenheart.simulation.technologies.hydrogen.h2_storage.salt_cavern.salt_cavern import (
+    SaltCavernStorage,
+)
 from greenheart.simulation.technologies.hydrogen.h2_storage.on_turbine.on_turbine_hydrogen_storage import (
     PressurizedTower,
 )
 
-from greenheart.simulation.technologies.hydrogen.h2_transport.h2_export_pipe import run_pipe_analysis
-from greenheart.simulation.technologies.hydrogen.h2_transport.h2_pipe_array import run_pipe_array_const_diam
+from greenheart.simulation.technologies.hydrogen.h2_transport.h2_export_pipe import (
+    run_pipe_analysis,
+)
+from greenheart.simulation.technologies.hydrogen.h2_transport.h2_pipe_array import (
+    run_pipe_array_const_diam,
+)
 from greenheart.simulation.technologies.offshore.fixed_platform import (
     FixedPlatformDesign,
     FixedPlatformInstallation,
@@ -31,22 +43,43 @@
 )
 from greenheart.simulation.technologies.offshore.all_platforms import calc_platform_opex
 
+
 def run_h2_pipe_array(
-    plant_config, orbit_project, electrolyzer_physics_results, design_scenario, verbose
+    greenheart_config,
+    hopp_config,
+    turbine_config,
+    wind_cost_results,
+    electrolyzer_physics_results,
+    design_scenario,
+    verbose,
 ):
-    if (design_scenario["transportation"] == "hvdc+pipeline" or (
+    if design_scenario["transportation"] == "hvdc+pipeline" or (
         design_scenario["electrolyzer_location"] == "turbine"
-        and not design_scenario["h2_storage_location"] == "turbine")
+        and not design_scenario["h2_storage_location"] == "turbine"
     ):
         # get pipe lengths from ORBIT using cable lengths (horizontal only)
-        pipe_lengths = orbit_project.phases["ArraySystemDesign"].sections_distance
+        if design_scenario["wind_location"] == "offshore":
+            pipe_lengths = wind_cost_results.orbit_project.phases[
+                "ArraySystemDesign"
+            ].sections_distance
+
+        if (
+            design_scenario["wind_location"] == "onshore"
+        ):  # TODO: improve pipe length estimate
+            raise NotImplementedError(
+                "distributed electrolysis is not implemented for onshore wind."
+            )
+            # np.ones_like(hopp_config["technologies"]["wind"]["num_turbines"])*(
+            #     greenheart_config["site"]["wind_layout"]["turbine_spacing"]
+            #     *turbine_config['rotor_diameter']
+            # )
 
         turbine_h2_flowrate = (
             max(
                 electrolyzer_physics_results["H2_Results"]["hydrogen_hourly_production"]
             )
             * ((1.0 / 60.0) ** 2)
-            / plant_config["plant"]["num_turbines"]
+            / hopp_config["technologies"]["wind"]["num_turbines"]
         )
         m_dot = (
             np.ones_like(pipe_lengths) * turbine_h2_flowrate
@@ -55,7 +88,7 @@ def run_h2_pipe_array(
             31  # Inlet pressure [bar] - assumed outlet pressure from electrolyzer model
         )
         p_outlet = 10  # Outlet pressure [bar] - about 20 bar drop
-        depth = plant_config["site"]["depth"]  # depth of pipe [m]
+        depth = greenheart_config["site"]["depth"]  # depth of pipe [m]
 
         capex, opex = run_pipe_array_const_diam(
             pipe_lengths, depth, p_inlet, p_outlet, m_dot
@@ -71,10 +104,13 @@ def run_h2_pipe_array(
 def run_h2_transport_compressor(
     greenheart_config, electrolyzer_physics_results, design_scenario, verbose=False
 ):
-    if (design_scenario["transportation"] == "pipeline" or 
-        design_scenario["transportation"] == "hvdc+pipeline" or (
-        design_scenario["h2_storage_location"] != "onshore"
-        and design_scenario["electrolyzer_location"] == "onshore")
+    if (
+        design_scenario["transportation"] == "pipeline"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+        or (
+            design_scenario["h2_storage_location"] != "onshore"
+            and design_scenario["electrolyzer_location"] == "onshore"
+        )
     ):
         ########## compressor model from Jamie Kee based on HDSAM
         flow_rate_kg_per_hr = max(
@@ -82,7 +118,9 @@ def run_h2_transport_compressor(
         )  # kg/hr
         number_of_compressors = 2  # a third will be added as backup in the code
         p_inlet = 20  # bar
-        p_outlet = greenheart_config["h2_transport_compressor"]["outlet_pressure"]  # bar
+        p_outlet = greenheart_config["h2_transport_compressor"][
+            "outlet_pressure"
+        ]  # bar
         flow_rate_kg_d = flow_rate_kg_per_hr * 24.0
 
         compressor = Compressor(
@@ -133,7 +171,11 @@ def run_h2_transport_compressor(
 
 
 def run_h2_transport_pipe(
-    orbit_config, greenheart_config, electrolyzer_physics_results, design_scenario, verbose=False
+    orbit_config,
+    greenheart_config,
+    electrolyzer_physics_results,
+    design_scenario,
+    verbose=False,
 ):
     # prepare inputs
     export_pipe_length = orbit_config["site"]["distance_to_landfall"]  # Length [km]
@@ -148,11 +190,13 @@ def run_h2_transport_pipe(
     p_outlet = greenheart_config["h2_transport_pipe"][
         "outlet_pressure"
     ]  # Outlet pressure [bar]
-    depth = orbit_config["site"]["depth"]  # depth of pipe [m]
+    depth = greenheart_config["site"]["depth"]  # depth of pipe [m]
 
     # run model
-    if (design_scenario["transportation"] == "pipeline" or 
-        design_scenario["transportation"] == "hvdc+pipeline") or (
+    if (
+        design_scenario["transportation"] == "pipeline"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+    ) or (
         design_scenario["h2_storage_location"] != "onshore"
         and design_scenario["electrolyzer_location"] == "onshore"
     ):
@@ -190,14 +234,14 @@ def run_h2_transport_pipe(
 
 
 def run_h2_storage(
-    orbit_config,
+    hopp_config,
     greenheart_config,
     turbine_config,
     electrolyzer_physics_results,
     design_scenario,
     verbose=False,
 ):
-    nturbines = orbit_config["plant"]["num_turbines"]
+    nturbines = hopp_config["technologies"]["wind"]["num_turbines"]
 
     if design_scenario["h2_storage_location"] == "platform":
         if (
@@ -224,7 +268,9 @@ def run_h2_storage(
             "section_heights": turbine_config["tower"]["section_heights"],
         }
 
-        h2_storage = PressurizedTower(orbit_config["atb_year"], turbine)
+        h2_storage = PressurizedTower(
+            greenheart_config["project_parameters"]["atb_year"], turbine
+        )
         h2_storage.run()
 
         h2_storage_capacity_single_turbine = h2_storage.get_capacity_H2()  # kg
@@ -258,7 +304,9 @@ def run_h2_storage(
                 "section_heights": turbine_config["tower"]["section_heights"],
             }
 
-            h2_storage = PressurizedTower(orbit_config["atb_year"], turbine)
+            h2_storage = PressurizedTower(
+                greenheart_config["project_parameters"]["atb_year"], turbine
+            )
             h2_storage.run()
 
             h2_storage_results["storage_capex"] = nturbines * h2_storage.get_capex()
@@ -272,12 +320,12 @@ def run_h2_storage(
                 )
                 print("storage pressure: ", h2_storage.get_pressure_H2())
 
-            h2_storage_results[
-                "storage_energy"
-            ] = 0.0  # low pressure, so no additional compression needed beyond electolyzer
+            h2_storage_results["storage_energy"] = (
+                0.0  # low pressure, so no additional compression needed beyond electolyzer
+            )
 
         elif greenheart_config["h2_storage"]["type"] == "pressure_vessel":
-            
+
             energy_cost = 0.0
 
             h2_storage = PressureVessel(Energy_cost=energy_cost)
@@ -306,9 +354,9 @@ def run_h2_storage(
             h2_storage_results["tank_footprint_m2"] = h2_storage.get_tank_footprint(
                 h2_capacity, upright=True
             )[1]
-            h2_storage_results[
-                "tank volume (m^3)"
-            ] = h2_storage.compressed_gas_function.Vtank
+            h2_storage_results["tank volume (m^3)"] = (
+                h2_storage.compressed_gas_function.Vtank
+            )
             h2_storage_results["Number of tanks"] = h2_storage.get_tanks(h2_capacity)
             if verbose:
                 print("ENERGY FOR STORAGE: ", energy * 1e-3 / (365 * 24), " MW")
@@ -335,7 +383,7 @@ def run_h2_storage(
             "h2_storage_compressor"
         ]["output_pressure"]
         storage_input["system_flow_rate"] = storage_max_fill_rate
-        storage_input["model"] = 'papadias'
+        storage_input["model"] = "papadias"
 
         # run pipe storage model
         h2_storage = UndergroundPipeStorage(storage_input)
@@ -343,7 +391,9 @@ def run_h2_storage(
         h2_storage.pipe_storage_capex()
         h2_storage.pipe_storage_opex()
 
-        h2_storage_results["storage_capex"] = h2_storage.output_dict["pipe_storage_capex"]
+        h2_storage_results["storage_capex"] = h2_storage.output_dict[
+            "pipe_storage_capex"
+        ]
         h2_storage_results["storage_opex"] = h2_storage.output_dict["pipe_storage_opex"]
         h2_storage_results["storage_energy"] = 0.0
 
@@ -352,7 +402,7 @@ def run_h2_storage(
         #     energy_cost = plant_config["project_parameters"]["ppa_price"]
         # else:
         #     energy_cost = 0.0
-        energy_cost = 0.0 # energy cost is now handled outside the storage model
+        energy_cost = 0.0  # energy cost is now handled outside the storage model
 
         h2_storage = PressureVessel(Energy_cost=energy_cost)
         h2_storage.run()
@@ -371,12 +421,12 @@ def run_h2_storage(
         h2_storage_results["tank_footprint_m2"] = h2_storage.get_tank_footprint(
             h2_capacity, upright=True
         )[1]
-        h2_storage_results[
-            "tank volume (m^3)"
-        ] = h2_storage.compressed_gas_function.Vtank
-        h2_storage_results[
-            "Number of tanks"
-        ] = h2_storage.compressed_gas_function.number_of_tanks
+        h2_storage_results["tank volume (m^3)"] = (
+            h2_storage.compressed_gas_function.Vtank
+        )
+        h2_storage_results["Number of tanks"] = (
+            h2_storage.compressed_gas_function.number_of_tanks
+        )
         if verbose:
             print("ENERGY FOR STORAGE: ", energy * 1e-3 / (365 * 24), " MW")
             print("Tank volume (M^3): ", h2_storage_results["tank volume (m^3)"])
@@ -393,7 +443,7 @@ def run_h2_storage(
         # pull parameters from plat_config file
         storage_input["H2_storage_kg"] = h2_capacity
         storage_input["system_flow_rate"] = storage_max_fill_rate
-        storage_input["model"] = 'papadias'
+        storage_input["model"] = "papadias"
 
         # run salt cavern storage model
         h2_storage = SaltCavernStorage(storage_input)
@@ -401,8 +451,12 @@ def run_h2_storage(
         h2_storage.salt_cavern_capex()
         h2_storage.salt_cavern_opex()
 
-        h2_storage_results["storage_capex"] = h2_storage.output_dict["salt_cavern_storage_capex"]
-        h2_storage_results["storage_opex"] = h2_storage.output_dict["salt_cavern_storage_opex"]
+        h2_storage_results["storage_capex"] = h2_storage.output_dict[
+            "salt_cavern_storage_capex"
+        ]
+        h2_storage_results["storage_opex"] = h2_storage.output_dict[
+            "salt_cavern_storage_opex"
+        ]
         h2_storage_results["storage_energy"] = 0.0
         # TODO replace this rough estimate with real numbers
         # h2_storage = None
@@ -422,7 +476,7 @@ def run_h2_storage(
         # pull parameters from plat_config file
         storage_input["H2_storage_kg"] = h2_capacity
         storage_input["system_flow_rate"] = storage_max_fill_rate
-        storage_input["model"] = 'papadias'
+        storage_input["model"] = "papadias"
 
         # run salt cavern storage model
         h2_storage = LinedRockCavernStorage(storage_input)
@@ -430,8 +484,12 @@ def run_h2_storage(
         h2_storage.lined_rock_cavern_capex()
         h2_storage.lined_rock_cavern_opex()
 
-        h2_storage_results["storage_capex"] = h2_storage.output_dict["lined_rock_cavern_storage_capex"]
-        h2_storage_results["storage_opex"] = h2_storage.output_dict["lined_rock_cavern_storage_opex"]
+        h2_storage_results["storage_capex"] = h2_storage.output_dict[
+            "lined_rock_cavern_storage_capex"
+        ]
+        h2_storage_results["storage_opex"] = h2_storage.output_dict[
+            "lined_rock_cavern_storage_opex"
+        ]
         h2_storage_results["storage_energy"] = 0.0
     else:
         raise (
@@ -448,13 +506,18 @@ def run_h2_storage(
                 h2_storage_results["storage_opex"]
             )
         )
-        print("H2 storage capacity (tonnes): ", h2_storage_results["h2_capacity"]/1000)
+        print(
+            "H2 storage capacity (tonnes): ", h2_storage_results["h2_capacity"] / 1000
+        )
         if h2_storage_results["h2_capacity"] > 0:
-            print("H2 storage cost $/kg of H2: ", h2_storage_results["storage_capex"]/h2_storage_results["h2_capacity"])
-        
+            print(
+                "H2 storage cost $/kg of H2: ",
+                h2_storage_results["storage_capex"] / h2_storage_results["h2_capacity"],
+            )
 
     return h2_storage, h2_storage_results
 
+
 def run_equipment_platform(
     hopp_config,
     greenheart_config,
@@ -512,7 +575,10 @@ def run_equipment_platform(
             topmass += solar_mass
 
         #### initialize
-        if greenheart_config["platform"]["design_phases"][0] == "FloatingPlatformDesign":
+        if (
+            greenheart_config["platform"]["design_phases"][0]
+            == "FloatingPlatformDesign"
+        ):
             if not ProjectManager.find_key_match("FloatingPlatformDesign"):
                 ProjectManager.register_design_phase(FloatingPlatformDesign)
             if not ProjectManager.find_key_match("FloatingPlatformInstallation"):
@@ -527,7 +593,7 @@ def run_equipment_platform(
 
         # assign site parameters
         if platform_config["site"]["depth"] == -1:
-            platform_config["site"]["depth"] = orbit_config["site"]["depth"]
+            platform_config["site"]["depth"] = greenheart_config["site"]["depth"]
         if platform_config["site"]["distance"] == -1:
             platform_config["site"]["distance"] = orbit_config["site"]["distance"]
         # assign equipment values
@@ -538,15 +604,15 @@ def run_equipment_platform(
             platform_config["equipment"]["tech_required_area"] = toparea
         platform = ProjectManager(platform_config)
         platform.run()
-        
-        design_capex = platform.design_results['platform_design']['total_cost']
+
+        design_capex = platform.design_results["platform_design"]["total_cost"]
         install_capex = platform.installation_capex
         total_capex = design_capex + install_capex
 
         total_opex = calc_platform_opex(total_capex, platform_config["opex_rate"])
 
-        platform_mass = platform.design_results['platform_design']['mass']
-        platform_area = platform.design_results['platform_design']['area']
+        platform_mass = platform.design_results["platform_design"]["mass"]
+        platform_area = platform.design_results["platform_design"]["area"]
 
     else:
         platform_mass = 0.0
diff --git a/greenheart/tools/eco/utilities.py b/greenheart/tools/eco/utilities.py
index 6be0f9840..ec9dde45f 100644
--- a/greenheart/tools/eco/utilities.py
+++ b/greenheart/tools/eco/utilities.py
@@ -26,8 +26,8 @@
 
 # Function to load inputs
 def get_inputs(
-    filename_hopp_config, 
-    filename_greenheart_config, 
+    filename_hopp_config,
+    filename_greenheart_config,
     filename_orbit_config,
     filename_turbine_config,
     filename_floris_config=None,
@@ -51,19 +51,26 @@ def get_inputs(
 
     # load hopp inputs
     hopp_config = load_yaml(filename_hopp_config)
-    
+
     # load eco inputs
     greenheart_config = load_yaml(filename_greenheart_config)
 
     # check that orbit and hopp inputs are compatible
-    if orbit_config["plant"]["capacity"] != hopp_config["technologies"]["wind"]["num_turbines"]*hopp_config["technologies"]["wind"]["turbine_rating_kw"]*1E-3:
-        raise(ValueError("Provided ORBIT and HOPP wind plant capacities do not match"))
+    if (
+        orbit_config["plant"]["capacity"]
+        != hopp_config["technologies"]["wind"]["num_turbines"]
+        * hopp_config["technologies"]["wind"]["turbine_rating_kw"]
+        * 1e-3
+    ):
+        raise (ValueError("Provided ORBIT and HOPP wind plant capacities do not match"))
 
     # update floris_config file with correct input from other files
     # load floris inputs
-    if hopp_config["technologies"]["wind"]["model_name"] == "floris":  # TODO replace elements of the file
+    if (
+        hopp_config["technologies"]["wind"]["model_name"] == "floris"
+    ):  # TODO replace elements of the file
         if filename_floris_config is None:
-            raise(ValueError("floris input file must be specified."))
+            raise (ValueError("floris input file must be specified."))
         else:
             floris_config = load_yaml(filename_floris_config)
             floris_config.update({"farm": {"turbine_type": turbine_config}})
@@ -77,14 +84,18 @@ def get_inputs(
             print(key, ": ", turbine_config[key])
 
     ############## provide custom layout for ORBIT and FLORIS if desired
-    
+
     if orbit_config["plant"]["layout"] == "custom":
         # generate ORBIT config from floris layout
-        for (i, x) in enumerate(floris_config["farm"]["layout_x"]):
+        for i, x in enumerate(floris_config["farm"]["layout_x"]):
             floris_config["farm"]["layout_x"][i] = x + 400
-        
-        layout_config, layout_data_location = convert_layout_from_floris_for_orbit(floris_config["farm"]["layout_x"], floris_config["farm"]["layout_y"], save_config=True)
-        
+
+        layout_config, layout_data_location = convert_layout_from_floris_for_orbit(
+            floris_config["farm"]["layout_x"],
+            floris_config["farm"]["layout_y"],
+            save_config=True,
+        )
+
         # update orbit_config with custom layout
         # orbit_config = orbit.core.library.extract_library_data(orbit_config, additional_keys=layout_config)
         orbit_config["array_system_design"]["location_data"] = layout_data_location
@@ -97,67 +108,87 @@ def get_inputs(
         elif tech == "wind":
             total_hybrid_plant_capacity_mw += orbit_config["plant"]["capacity"]
         elif tech == "pv":
-            total_hybrid_plant_capacity_mw += hopp_config["technologies"][tech]["system_capacity_kw"]*1E-3
+            total_hybrid_plant_capacity_mw += (
+                hopp_config["technologies"][tech]["system_capacity_kw"] * 1e-3
+            )
         elif tech == "wave":
-            total_hybrid_plant_capacity_mw += hopp_config["technologies"][tech]["num_devices"]*hopp_config["technologies"][tech]["device_rating_kw"]*1E-3
+            total_hybrid_plant_capacity_mw += (
+                hopp_config["technologies"][tech]["num_devices"]
+                * hopp_config["technologies"][tech]["device_rating_kw"]
+                * 1e-3
+            )
 
     # initialize dict for hybrid plant
     if total_hybrid_plant_capacity_mw != orbit_config["plant"]["capacity"]:
         orbit_hybrid_electrical_export_config = copy.deepcopy(orbit_config)
-        orbit_hybrid_electrical_export_config["plant"]["capacity"] = total_hybrid_plant_capacity_mw
-        orbit_hybrid_electrical_export_config["plant"].pop("num_turbines") # allow orbit to set num_turbines later based on the new hybrid capacity and turbine rating
+        orbit_hybrid_electrical_export_config["plant"][
+            "capacity"
+        ] = total_hybrid_plant_capacity_mw
+        orbit_hybrid_electrical_export_config["plant"].pop(
+            "num_turbines"
+        )  # allow orbit to set num_turbines later based on the new hybrid capacity and turbine rating
     else:
         orbit_hybrid_electrical_export_config = {}
 
     if verbose:
-        print(f"Total hybrid plant rating calculated: {total_hybrid_plant_capacity_mw} MW")
+        print(
+            f"Total hybrid plant rating calculated: {total_hybrid_plant_capacity_mw} MW"
+        )
 
     ############## return all inputs
 
-    return hopp_config, greenheart_config, orbit_config, turbine_config, floris_config, orbit_hybrid_electrical_export_config
+    return (
+        hopp_config,
+        greenheart_config,
+        orbit_config,
+        turbine_config,
+        floris_config,
+        orbit_hybrid_electrical_export_config,
+    )
+
 
 def convert_layout_from_floris_for_orbit(turbine_x, turbine_y, save_config=False):
-    
-    turbine_x_km = (np.array(turbine_x)*1E-3).tolist()
-    turbine_y_km = (np.array(turbine_y)*1E-3).tolist()
+
+    turbine_x_km = (np.array(turbine_x) * 1e-3).tolist()
+    turbine_y_km = (np.array(turbine_y) * 1e-3).tolist()
 
     # initialize dict with data for turbines
     turbine_dict = {
-                'id': list(range(0,len(turbine_x))),
-                'substation_id': ['OSS']*len(turbine_x),
-                'name': list(range(0,len(turbine_x))),
-                'longitude': turbine_x_km,
-                'latitude': turbine_y_km,
-                'string': [0]*len(turbine_x), # can be left empty
-                'order': [0]*len(turbine_x), # can be left empty
-                'cable_length': [0]*len(turbine_x),
-                'bury_speed': [0]*len(turbine_x)
-                }
+        "id": list(range(0, len(turbine_x))),
+        "substation_id": ["OSS"] * len(turbine_x),
+        "name": list(range(0, len(turbine_x))),
+        "longitude": turbine_x_km,
+        "latitude": turbine_y_km,
+        "string": [0] * len(turbine_x),  # can be left empty
+        "order": [0] * len(turbine_x),  # can be left empty
+        "cable_length": [0] * len(turbine_x),
+        "bury_speed": [0] * len(turbine_x),
+    }
     string_counter = -1
     order_counter = 0
     for i in range(0, len(turbine_x)):
         if turbine_x[i] - 400 == 0:
             string_counter += 1
             order_counter = 0
-        
+
         turbine_dict["order"][i] = order_counter
         turbine_dict["string"][i] = string_counter
 
         order_counter += 1
-    
+
     # initialize dict with substation information
     substation_dict = {
-                'id': 'OSS',
-                'substation_id': 'OSS',
-                'name': 'OSS',
-                'longitude': np.min(turbine_x_km)-200*1e-3,
-                'latitude': np.average(turbine_y_km),
-                'string': "" , # can be left empty
-                'order': "", # can be left empty
-                'cable_length': "",
-                'bury_speed': ""
-                }
-    
+        "id": "OSS",
+        "substation_id": "OSS",
+        "name": "OSS",
+        "longitude": np.min(turbine_x_km) - 200 * 1e-3,
+        "latitude": np.average(turbine_y_km),
+        "string": "",  # can be left empty
+        "order": "",  # can be left empty
+        "cable_length": "",
+        "bury_speed": "",
+    }
+
     # combine turbine and substation dicts
     for key in turbine_dict.keys():
         # turbine_dict[key].append(substation_dict[key])
@@ -172,19 +203,20 @@ def convert_layout_from_floris_for_orbit(turbine_x, turbine_y, save_config=False
             os.makedirs(save_location)
         # create pandas data frame
         df = pd.DataFrame.from_dict(turbine_dict)
-        
+
         # df.drop("index")
         df.set_index("id")
 
         # save to csv
-        df.to_csv(save_location+file_name+".csv", index=False)
+        df.to_csv(save_location + file_name + ".csv", index=False)
 
     return turbine_dict, file_name
 
+
 def visualize_plant(
     hopp_config,
     greenheart_config,
-    orbit_project,
+    wind_cost_outputs,
     hopp_results,
     platform_results,
     desal_results,
@@ -229,44 +261,44 @@ def visualize_plant(
 
     # get cable/pipe locations
     cable_array_points = (
-        orbit_project.phases["ArraySystemDesign"].coordinates * 1e3
+        wind_cost_outputs.orbit_project.phases["ArraySystemDesign"].coordinates * 1e3
     )  # ORBIT gives coordinates in km, convert to m
     pipe_array_points = (
-        orbit_project.phases["ArraySystemDesign"].coordinates * 1e3
+        wind_cost_outputs.orbit_project.phases["ArraySystemDesign"].coordinates * 1e3
     )  # ORBIT gives coordinates in km, convert to m
 
     # get turbine rotor diameter
-    rotor_diameter = orbit_project.config["turbine"]["rotor_diameter"]  # in m
+    rotor_diameter = wind_cost_outputs.orbit_project.config["turbine"]["rotor_diameter"]  # in m
     rotor_radius = rotor_diameter / 2.0
 
     # get turbine tower base diameter
-    tower_base_diameter = orbit_project.config["turbine"]["tower"]["section_diameters"][
+    tower_base_diameter = wind_cost_outputs.orbit_project.config["turbine"]["tower"]["section_diameters"][
         0
     ]  # in m
     tower_base_radius = tower_base_diameter / 2.0
 
     # get turbine locations
     turbine_x = (
-        orbit_project.phases["ArraySystemDesign"].turbines_x.flatten() * 1e3
+        wind_cost_outputs.orbit_project.phases["ArraySystemDesign"].turbines_x.flatten() * 1e3
     )  # ORBIT gives coordinates in km, convert to m
     turbine_x = turbine_x[~np.isnan(turbine_x)]
     turbine_y = (
-        orbit_project.phases["ArraySystemDesign"].turbines_y.flatten() * 1e3
+        wind_cost_outputs.orbit_project.phases["ArraySystemDesign"].turbines_y.flatten() * 1e3
     )  # ORBIT gives coordinates in km, convert to m
     turbine_y = turbine_y[~np.isnan(turbine_y)]
 
     # get offshore substation location and dimensions
     substation_x = (
-        orbit_project.phases["ArraySystemDesign"].oss_x * 1e3
+        wind_cost_outputs.orbit_project.phases["ArraySystemDesign"].oss_x * 1e3
     )  # ORBIT gives coordinates in km, convert to m (treated as center)
     substation_y = (
-        orbit_project.phases["ArraySystemDesign"].oss_y * 1e3
+        wind_cost_outputs.orbit_project.phases["ArraySystemDesign"].oss_y * 1e3
     )  # ORBIT gives coordinates in km, convert to m (treated as center)
     substation_side_length = 20  # [m] just based on a large substation (https://www.windpowerengineering.com/making-modern-offshore-substation/) since the dimensions are not available in ORBIT
 
     # set onshore substation dimensions
-    onshore_substation_x_side_length = 127.25 # [m] based on 1 acre area https://www.power-technology.com/features/making-space-for-power-how-much-land-must-renewables-use/
-    onshore_substation_y_side_length = 31.8 # [m] based on 1 acre area https://www.power-technology.com/features/making-space-for-power-how-much-land-must-renewables-use/
+    onshore_substation_x_side_length = 127.25  # [m] based on 1 acre area https://www.power-technology.com/features/making-space-for-power-how-much-land-must-renewables-use/
+    onshore_substation_y_side_length = 31.8  # [m] based on 1 acre area https://www.power-technology.com/features/making-space-for-power-how-much-land-must-renewables-use/
 
     # get equipment platform location and dimensions
     equipment_platform_area = platform_results["toparea_m2"]
@@ -294,7 +326,7 @@ def visualize_plant(
 
     electrolyzer_area = electrolyzer_physics_results["equipment_footprint_m2"]
     if design_scenario["electrolyzer_location"] == "turbine":
-        electrolyzer_area /= orbit_project.config["plant"]["num_turbines"]
+        electrolyzer_area /= wind_cost_outputs.orbit_project.config["plant"]["num_turbines"]
     electrolyzer_side = np.sqrt(electrolyzer_area)
 
     # compressor side # not sized
@@ -355,9 +387,9 @@ def visualize_plant(
     ax[1, 1].add_patch(turbine_patch11_tower)
 
     # add pipe array
-    if (design_scenario["transportation"] == "hvdc+pipeline" or 
-        (design_scenario["h2_storage_location"] != "turbine"
-        and design_scenario["electrolyzer_location"] == "turbine")
+    if design_scenario["transportation"] == "hvdc+pipeline" or (
+        design_scenario["h2_storage_location"] != "turbine"
+        and design_scenario["electrolyzer_location"] == "turbine"
     ):
         i = 0
         for point_string in pipe_array_points:
@@ -395,8 +427,10 @@ def visualize_plant(
             )
 
     ## add cables
-    if (design_scenario["h2_storage_location"] != "turbine" or 
-        design_scenario["transportation"] == "hvdc+pipeline"):
+    if (
+        design_scenario["h2_storage_location"] != "turbine"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+    ):
         i = 0
         for point_string in cable_array_points:
             if i == 0:
@@ -433,8 +467,10 @@ def visualize_plant(
             )
 
     ## add offshore substation
-    if (design_scenario["h2_storage_location"] != "turbine" or 
-        design_scenario["transportation"] == "hvdc+pipeline"):
+    if (
+        design_scenario["h2_storage_location"] != "turbine"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+    ):
         substation_patch01 = patches.Rectangle(
             (
                 substation_x - substation_side_length,
@@ -495,8 +531,17 @@ def visualize_plant(
         ax[1, 0].add_patch(equipment_platform_patch10)
 
     ## add hvdc cable
-    if design_scenario["transportation"] == "hvdc" or design_scenario["transportation"] == "hvdc+pipeline":
-        ax[0, 0].plot([onshorex+onshore_substation_x_side_length, 1000], [48, 48], "--", color=cable_color, label="HVDC Cable")
+    if (
+        design_scenario["transportation"] == "hvdc"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+    ):
+        ax[0, 0].plot(
+            [onshorex + onshore_substation_x_side_length, 1000],
+            [48, 48],
+            "--",
+            color=cable_color,
+            label="HVDC Cable",
+        )
         ax[0, 1].plot(
             [-5000, substation_x],
             [substation_y - 100, substation_y - 100],
@@ -515,11 +560,14 @@ def visualize_plant(
         )
 
     ## add onshore substation
-    if design_scenario["transportation"] == "hvdc" or design_scenario["transportation"] == "hvdc+pipeline":
+    if (
+        design_scenario["transportation"] == "hvdc"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+    ):
         onshore_substation_patch00 = patches.Rectangle(
             (
-                onshorex + 0.2*onshore_substation_y_side_length,
-                onshorey - onshore_substation_y_side_length*1.2,
+                onshorex + 0.2 * onshore_substation_y_side_length,
+                onshorey - onshore_substation_y_side_length * 1.2,
             ),
             onshore_substation_x_side_length,
             onshore_substation_y_side_length,
@@ -531,9 +579,10 @@ def visualize_plant(
         ax[0, 0].add_patch(onshore_substation_patch00)
 
     ## add transport pipeline
-    if (design_scenario["transportation"] == "pipeline" or 
-        design_scenario["transportation"] == "hvdc+pipeline" or 
-        (
+    if (
+        design_scenario["transportation"] == "pipeline"
+        or design_scenario["transportation"] == "hvdc+pipeline"
+        or (
             design_scenario["transportation"] == "hvdc"
             and design_scenario["h2_storage_location"] == "platform"
         )
@@ -570,12 +619,9 @@ def visualize_plant(
         )
 
         if (
-            (
-                design_scenario["transportation"] == "hvdc" or 
-                design_scenario["transportation"] == "hvdc+pipeline"
-            )
-            and design_scenario["h2_storage_location"] == "platform"
-        ):
+            design_scenario["transportation"] == "hvdc"
+            or design_scenario["transportation"] == "hvdc+pipeline"
+        ) and design_scenario["h2_storage_location"] == "platform":
             h2cx = onshorex - compressor_side
             h2cy = onshorey - compressor_side + 2
             h2cax = ax[0, 0]
@@ -740,7 +786,7 @@ def visualize_plant(
         )
         ax[1, 0].add_patch(h2_storage_patch)
     elif design_scenario["h2_storage_location"] == "turbine":
-    
+
         if greenheart_config["h2_storage"]["type"] == "turbine":
             h2_storage_patch = patches.Circle(
                 (turbine_x[0], turbine_y[0]),
@@ -767,10 +813,16 @@ def visualize_plant(
                 )
                 ax[0, 1].add_patch(h2_storage_patch)
         elif greenheart_config["h2_storage"]["type"] == "pressure_vessel":
-            h2_storage_side = np.sqrt(h2_storage_area/greenheart_config["plant"]["num_turbines"])
+            h2_storage_side = np.sqrt(
+                h2_storage_area / greenheart_config["plant"]["num_turbines"]
+            )
             h2_storage_patch = patches.Rectangle(
-                (turbine_x[0] - h2_storage_side - desal_equipment_side, turbine_y[0] + tower_base_radius),
-                width=h2_storage_side, height=h2_storage_side,
+                (
+                    turbine_x[0] - h2_storage_side - desal_equipment_side,
+                    turbine_y[0] + tower_base_radius,
+                ),
+                width=h2_storage_side,
+                height=h2_storage_side,
                 color=h2_storage_color,
                 fill=None,
                 label="H$_2$ Storage",
@@ -784,8 +836,12 @@ def visualize_plant(
                 else:
                     slable = None
                 h2_storage_patch = patches.Rectangle(
-                    (turbine_x[i] - h2_storage_side - desal_equipment_side, turbine_y[i] + tower_base_radius),
-                    width=h2_storage_side, height=h2_storage_side,
+                    (
+                        turbine_x[i] - h2_storage_side - desal_equipment_side,
+                        turbine_y[i] + tower_base_radius,
+                    ),
+                    width=h2_storage_side,
+                    height=h2_storage_side,
                     color=h2_storage_color,
                     fill=None,
                     label=slable,
@@ -834,11 +890,11 @@ def visualize_plant(
     ## add solar
     if hopp_config["site"]["solar"]:
         solar_side_y = equipment_platform_side_length
-        solar_side_x = hopp_results["hybrid_plant"].pv.footprint_area/solar_side_y
+        solar_side_x = hopp_results["hybrid_plant"].pv.footprint_area / solar_side_y
 
         solarx = equipment_platform_x - equipment_platform_side_length / 2
         solary = equipment_platform_y - equipment_platform_side_length / 2
-        
+
         solar_patch = patches.Rectangle(
             (solarx, solary),
             solar_side_x,
@@ -854,14 +910,19 @@ def visualize_plant(
     if hopp_config["site"]["wave"]:
         # get wave generation area geometry
         num_devices = hopp_config["technologies"]["wave"]["num_devices"]
-        distance_to_shore = hopp_config["technologies"]["wave"]["cost_inputs"]["distance_to_shore"]*1E3
+        distance_to_shore = (
+            hopp_config["technologies"]["wave"]["cost_inputs"]["distance_to_shore"]
+            * 1e3
+        )
         number_rows = hopp_config["technologies"]["wave"]["cost_inputs"]["number_rows"]
-        device_spacing = hopp_config["technologies"]["wave"]["cost_inputs"]["device_spacing"]
+        device_spacing = hopp_config["technologies"]["wave"]["cost_inputs"][
+            "device_spacing"
+        ]
         row_spacing = hopp_config["technologies"]["wave"]["cost_inputs"]["row_spacing"]
 
         # calculate wave generation area dimenstions
-        wave_side_y = device_spacing*np.ceil(num_devices/number_rows)
-        wave_side_x = row_spacing*(number_rows)
+        wave_side_y = device_spacing * np.ceil(num_devices / number_rows)
+        wave_side_x = row_spacing * (number_rows)
 
         # generate wave generation patch
         wavex = substation_x - wave_side_x
@@ -874,7 +935,7 @@ def visualize_plant(
             fill=None,
             label="Wave Array",
             hatch=wave_hatch,
-            zorder=1
+            zorder=1,
         )
         ax[0, 1].add_patch(wave_patch)
 
@@ -882,15 +943,25 @@ def visualize_plant(
         wave_export_cable_coords_x = [substation_x, substation_x]
         wave_export_cable_coords_y = [substation_y, substation_y + distance_to_shore]
 
-        ax[0, 1].plot(wave_export_cable_coords_x, wave_export_cable_coords_y, cable_color, zorder=0)
-        ax[1, 0].plot(wave_export_cable_coords_x, wave_export_cable_coords_y, cable_color, zorder=0)
+        ax[0, 1].plot(
+            wave_export_cable_coords_x,
+            wave_export_cable_coords_y,
+            cable_color,
+            zorder=0,
+        )
+        ax[1, 0].plot(
+            wave_export_cable_coords_x,
+            wave_export_cable_coords_y,
+            cable_color,
+            zorder=0,
+        )
 
     ax[0, 0].set(xlim=[0, 400], ylim=[0, 300])
     ax[0, 0].set(aspect="equal")
 
     allpoints = cable_array_points.flatten()
     allpoints = allpoints[~np.isnan(allpoints)]
-    
+
     roundto = -3
     ax[0, 1].set(
         xlim=[
@@ -928,11 +999,17 @@ def visualize_plant(
             round(
                 turbine_x[0] - tower_base_radius - tower_buffer0 - 50, ndigits=roundto
             ),
-            round(turbine_x[0] + tower_base_radius + 3*tower_buffer1, ndigits=roundto),
+            round(
+                turbine_x[0] + tower_base_radius + 3 * tower_buffer1, ndigits=roundto
+            ),
         ],
         ylim=[
-            round(turbine_y[0] - tower_base_radius - 2*tower_buffer0, ndigits=roundto),
-            round(turbine_y[0] + tower_base_radius + 4*tower_buffer1, ndigits=roundto),
+            round(
+                turbine_y[0] - tower_base_radius - 2 * tower_buffer0, ndigits=roundto
+            ),
+            round(
+                turbine_y[0] + tower_base_radius + 4 * tower_buffer1, ndigits=roundto
+            ),
         ],
     )
     ax[1, 1].set(aspect="equal")
@@ -948,7 +1025,7 @@ def visualize_plant(
         "(d) NW-most wind turbine",
     ]
     for axi, label in zip(ax.flatten(), labels):
-        axi.legend(frameon=False)#, ncol=2, loc="best")
+        axi.legend(frameon=False)  # , ncol=2, loc="best")
         axi.set(xlabel="Easting (m)", ylabel="Northing (m)")
         axi.set_title(label, loc="left")
         # axi.spines[['right', 'top']].set_visible(False)
@@ -966,20 +1043,29 @@ def visualize_plant(
         plt.show()
     return 0
 
-def save_power_series(hybrid_plant: HoppInterface.system, ax=None, simulation_length=8760):
+
+def save_power_series(
+    hybrid_plant: HoppInterface.system, ax=None, simulation_length=8760
+):
 
     if ax == None:
         fig, ax = plt.subplots(1)
 
     output = {}
     if hybrid_plant.pv:
-        solar_plant_power = np.array(hybrid_plant.pv.generation_profile[0:simulation_length])
+        solar_plant_power = np.array(
+            hybrid_plant.pv.generation_profile[0:simulation_length]
+        )
         output.update({"pv": solar_plant_power})
     if hybrid_plant.wind:
-        wind_plant_power = np.array(hybrid_plant.wind.generation_profile[0:simulation_length])
+        wind_plant_power = np.array(
+            hybrid_plant.wind.generation_profile[0:simulation_length]
+        )
         output.update({"wind": wind_plant_power})
     if hybrid_plant.wave:
-        wave_plant_power = np.array(hybrid_plant.wave.generation_profile[0:simulation_length])
+        wave_plant_power = np.array(
+            hybrid_plant.wave.generation_profile[0:simulation_length]
+        )
         output.update({"wave": wave_plant_power})
     if hybrid_plant.battery:
         battery_power_out = hybrid_plant.battery.outputs.dispatch_P
@@ -995,6 +1081,7 @@ def save_power_series(hybrid_plant: HoppInterface.system, ax=None, simulation_le
 
     return 0
 
+
 # set up function to post-process HOPP results
 def post_process_simulation(
     lcoe,
@@ -1009,7 +1096,7 @@ def post_process_simulation(
     h2_storage_results,
     capex_breakdown,
     opex_breakdown,
-    orbit_project,
+    wind_cost_results,
     platform_results,
     desal_results,
     design_scenario,
@@ -1069,7 +1156,7 @@ def post_process_simulation(
         visualize_plant(
             hopp_config,
             greenheart_config,
-            orbit_project,
+            wind_cost_results,
             hopp_results,
             platform_results,
             desal_results,
@@ -1087,11 +1174,19 @@ def post_process_simulation(
             os.mkdir(sp)
     pf_lcoh.get_cost_breakdown().to_csv(
         "data/lcoh/cost_breakdown_lcoh_design%i_incentive%i_%sstorage.csv"
-        % (plant_design_number, incentive_option, greenheart_config["h2_storage"]["type"])
+        % (
+            plant_design_number,
+            incentive_option,
+            greenheart_config["h2_storage"]["type"],
+        )
     )
     pf_lcoe.get_cost_breakdown().to_csv(
         "data/lcoe/cost_breakdown_lcoe_design%i_incentive%i_%sstorage.csv"
-        % (plant_design_number, incentive_option, greenheart_config["h2_storage"]["type"])
+        % (
+            plant_design_number,
+            incentive_option,
+            greenheart_config["h2_storage"]["type"],
+        )
     )
 
     # create dataframe for saving all the stuff
@@ -1103,7 +1198,9 @@ def post_process_simulation(
     if len(solver_results) > 0:
         hours = len(hopp_results["combined_hybrid_power_production_hopp"])
         annual_energy_breakdown = {
-            "electricity_generation_kwh": sum(hopp_results["combined_hybrid_power_production_hopp"]),
+            "electricity_generation_kwh": sum(
+                hopp_results["combined_hybrid_power_production_hopp"]
+            ),
             "electrolyzer_kwh": sum(
                 electrolyzer_physics_results["energy_to_electrolyzer_kw"]
             ),
@@ -1115,14 +1212,18 @@ def post_process_simulation(
         }
 
     ######################### save detailed ORBIT cost information
-    _, orbit_capex_breakdown, wind_capex_multiplier = adjust_orbit_costs(orbit_project=orbit_project, greenheart_config=greenheart_config)
-    
+    _, orbit_capex_breakdown, wind_capex_multiplier = adjust_orbit_costs(
+        orbit_project=wind_cost_results.orbit_project,
+        greenheart_config=greenheart_config,
+    )
+
     # orbit_capex_breakdown["Onshore Substation"] = orbit_project.phases["ElectricalDesign"].onshore_cost
     # discount ORBIT cost information
     for key in orbit_capex_breakdown:
         orbit_capex_breakdown[key] = -npf.fv(
             greenheart_config["finance_parameters"]["general_inflation"],
-            orbit_config["cost_year"]-greenheart_config["finance_parameters"]["discount_years"]["wind"],
+            greenheart_config["project_parameters"]["cost_year"]
+            - greenheart_config["finance_parameters"]["discount_years"]["wind"],
             0.0,
             orbit_capex_breakdown[key],
         )
@@ -1132,25 +1233,41 @@ def post_process_simulation(
     savedir = "data/orbit_costs/"
     if not os.path.exists(savedir):
         os.makedirs(savedir)
-    ob_df.to_csv(savedir+"orbit_cost_breakdown_lcoh_design%i_incentive%i_%sstorage.csv"
-        % (plant_design_number, incentive_option, greenheart_config["h2_storage"]["type"]))
+    ob_df.to_csv(
+        savedir
+        + "orbit_cost_breakdown_lcoh_design%i_incentive%i_%sstorage.csv"
+        % (
+            plant_design_number,
+            incentive_option,
+            greenheart_config["h2_storage"]["type"],
+        )
+    )
     ###############################
 
     ###################### Save export system breakdown from ORBIT ###################
-    
-    _, orbit_capex_breakdown, wind_capex_multiplier = adjust_orbit_costs(orbit_project=orbit_project, greenheart_config=greenheart_config)
-    
-    onshore_substation_costs = orbit_project.phases["ElectricalDesign"].onshore_cost*wind_capex_multiplier
-    
+
+    _, orbit_capex_breakdown, wind_capex_multiplier = adjust_orbit_costs(
+        orbit_project=wind_cost_results.orbit_project,
+        greenheart_config=greenheart_config,
+    )
+
+    onshore_substation_costs = (
+        wind_cost_results.orbit_project.phases["ElectricalDesign"].onshore_cost
+        * wind_capex_multiplier
+    )
+
     orbit_capex_breakdown["Export System Installation"] -= onshore_substation_costs
 
-    orbit_capex_breakdown["Onshore Substation and Installation"] = onshore_substation_costs
+    orbit_capex_breakdown["Onshore Substation and Installation"] = (
+        onshore_substation_costs
+    )
 
     # discount ORBIT cost information
     for key in orbit_capex_breakdown:
         orbit_capex_breakdown[key] = -npf.fv(
             greenheart_config["finance_parameters"]["general_inflation"],
-            orbit_config["cost_year"]-greenheart_config["finance_parameters"]["discount_years"]["wind"],
+            greenheart_config["project_parameters"]["cost_year"]
+            - greenheart_config["finance_parameters"]["discount_years"]["wind"],
             0.0,
             orbit_capex_breakdown[key],
         )
@@ -1160,29 +1277,47 @@ def post_process_simulation(
     savedir = "data/orbit_costs/"
     if not os.path.exists(savedir):
         os.makedirs(savedir)
-    ob_df.to_csv(savedir+"orbit_cost_breakdown_with_onshore_substation_lcoh_design%i_incentive%i_%sstorage.csv"
-        % (plant_design_number, incentive_option, greenheart_config["h2_storage"]["type"]))
+    ob_df.to_csv(
+        savedir
+        + "orbit_cost_breakdown_with_onshore_substation_lcoh_design%i_incentive%i_%sstorage.csv"
+        % (
+            plant_design_number,
+            incentive_option,
+            greenheart_config["h2_storage"]["type"],
+        )
+    )
 
     ##################################################################################
-    if hasattr(hopp_results["hybrid_plant"], 'dispatch_builder') and hopp_results["hybrid_plant"].battery:
-        plot_tools.plot_generation_profile(hopp_results["hybrid_plant"],
-                                    start_day= 0,
-                                    n_days= 10,
-                                    plot_filename=os.path.abspath("./figures/production/generation_profile.pdf"),
-                                    font_size=14,
-                                    power_scale=1/1000,
-                                    solar_color='r',
-                                    wind_color='b',
-                                    wave_color='g',
-                                    discharge_color='b',
-                                    charge_color='r',
-                                    gen_color='g',
-                                    price_color='r',
-                                    show_price=False
-                                    )
+    if (
+        hasattr(hopp_results["hybrid_plant"], "dispatch_builder")
+        and hopp_results["hybrid_plant"].battery
+    ):
+        savedir = "figures/production/"
+        if not os.path.exists(savedir):
+            os.makedirs(savedir)
+        plot_tools.plot_generation_profile(
+            hopp_results["hybrid_plant"],
+            start_day=0,
+            n_days=10,
+            plot_filename=os.path.abspath(
+                "./figures/production/generation_profile.pdf"
+            ),
+            font_size=14,
+            power_scale=1 / 1000,
+            solar_color="r",
+            wind_color="b",
+            wave_color="g",
+            discharge_color="b",
+            charge_color="r",
+            gen_color="g",
+            price_color="r",
+            show_price=False,
+        )
     else:
-        print("generation profile not plotted because HoppInterface does not have a 'dispatch_builder'")
-    
+        print(
+            "generation profile not plotted because HoppInterface does not have a 'dispatch_builder'"
+        )
+
     # save production information
     save_power_series(hopp_results["hybrid_plant"])
 
diff --git a/hopp/simulation/technologies/financial/custom_financial_model.py b/hopp/simulation/technologies/financial/custom_financial_model.py
index df1d76780..0aa19d951 100644
--- a/hopp/simulation/technologies/financial/custom_financial_model.py
+++ b/hopp/simulation/technologies/financial/custom_financial_model.py
@@ -121,6 +121,7 @@ class Outputs(FinancialData):
 class SystemOutput(FinancialData):
     gen: Sequence = field(default=(0,))
     system_capacity: float= field(default=None)
+    annual_energy: float= field(default=None)
     degradation: Sequence= field(default=(0,))
     system_pre_curtailment_kwac: float= field(default=None)
     annual_energy_pre_curtailment_ac: float= field(default=None)
@@ -202,7 +203,7 @@ def set_financial_inputs(self, system_model=None):
         This custom financial model needs to be able to update its inputs from the system model, as
         parameters are not linked like they are when a PySAM.Singleowner model is created using
         from_existing(). The inputs that need to be updated will depend on the financial model
-        implementation, and these are specified here. The system model reference is also update
+        implementation, and these are specified here. The system model reference is also updated
         here, as the system model is not always available during __init__.
         """
         if system_model is not None:
@@ -217,7 +218,6 @@ def set_financial_inputs(self, system_model=None):
         if 'system_capacity' in power_source_dict:
             self.value('system_capacity', power_source_dict['system_capacity'])
 
-
     def execute(self, n=0):
         self.set_financial_inputs()         # update inputs from system model
         npv = self.npv(
@@ -290,12 +290,15 @@ def net_cash_flow(self, project_life=25):
         ncf = list()
         ncf.append(-self.value('total_installed_cost'))
         degrad_fraction = 1                         # fraction of annual energy after degradation
-        for year in range(1, project_life + 1):
+        om_costs = self.o_and_m_cost()
+        self.cf_operating_expenses = np.asarray([om_costs*(1 + self.value('inflation_rate') / 100)**(year - 1) for year in range(1, project_life+1)])
+        self.cf_utility_bill = np.zeros_like(self.cf_operating_expenses) #TODO make it possible for this to be non-zero
+        for i, year in enumerate(range(1, project_life + 1)):
             degrad_fraction *= (1 - degradation[year - 1])
             ncf.append(
                         (
-                        - self.o_and_m_cost()
-                        * (1 + self.value('inflation_rate') / 100)**(year - 1)
+                        - self.cf_operating_expenses[i]
+                        - self.cf_utility_bill[i]
                         + self.value('annual_energy')
                         * degrad_fraction
                         * self.value('ppa_price_input')[0]
@@ -309,11 +312,11 @@ def o_and_m_cost(self):
         """
         Computes the annual O&M cost from the fixed, per capacity and per production costs
         """
+        
         return self.value('om_fixed')[0] \
                + self.value('om_capacity')[0] * self.value('system_capacity') \
                + self.value('om_production')[0] * self.value('annual_energy') * 1e-3
 
-
     def value(self, var_name, var_value=None):
         attr_obj = None
         if var_name in self.__dir__():
diff --git a/hopp/simulation/technologies/wind/floris.py b/hopp/simulation/technologies/wind/floris.py
index 08248a184..2d1f48300 100644
--- a/hopp/simulation/technologies/wind/floris.py
+++ b/hopp/simulation/technologies/wind/floris.py
@@ -1,5 +1,6 @@
 # tools to add floris to the hybrid simulation class
 from attrs import define, field
+from dataclasses import dataclass, asdict
 import csv
 from typing import TYPE_CHECKING, Tuple
 import numpy as np
@@ -20,9 +21,10 @@ class Floris(BaseClass):
     site: SiteInfo = field()
     config: "WindConfig" = field()
 
+    _operational_losses: float = field(init=False)
     _timestep: Tuple[int, int] = field(init=False)
+    annual_energy_pre_curtailment_ac: float = field(init=False)
     fi: FlorisInterface = field(init=False)
-    _operational_losses: float = field(init=False)
 
     def __attrs_post_init__(self):
         # floris_input_file = resource_file_converter(self.config["simulation_input_file"])
@@ -134,6 +136,16 @@ def execute(self, project_life):
 
         self.annual_energy = np.sum(self.gen) # kWh
         self.capacity_factor = np.sum(self.gen) / (8760 * self.system_capacity) * 100
-
         self.turb_powers = power_turbines * (100 - self._operational_losses) / 100 / 1000 # kW
-        self.turb_velocities = self.fi.turbine_average_velocities
\ No newline at end of file
+        self.turb_velocities = self.fi.turbine_average_velocities
+        self.annual_energy_pre_curtailment_ac = self.annual_energy
+
+    def export(self):
+        """
+        Return all the floris system configuration in a dictionary for the financial model
+        """
+        config = {
+            'system_capacity': self.system_capacity,
+            'annual_energy': self.annual_energy,
+        }
+        return config
\ No newline at end of file


Test patch:
diff --git a/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config.yaml b/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config.yaml
index 63286ee9f..431141bdf 100644
--- a/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config.yaml
+++ b/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config.yaml
@@ -1,9 +1,17 @@
 site:
   mean_windspeed: False 
+  depth: 45 #m
+  wind_layout:
+    row_spacing: 7  # Also defined in ORBIT config for offshore layout. Greenheart config values override the values in ORBIT.
+    turbine_spacing: 7 # Also defined in ORBIT config for offshore layout. Greenheart config values override the values in ORBIT.
+    grid_angle: 0 # wind layout grid angle in degrees where 0 is north, increasing clockwise
+    row_phase_offset: 0 # wind layout offset of turbines along row from one row to the next
 project_parameters:
+  project_lifetime: 30
   grid_connection: False # option, can be turned on or off
   ppa_price: 0.025 # $/kWh based on 2022 land based wind market report (ERCOT area ppa prices) https://www.energy.gov/sites/default/files/2022-08/land_based_wind_market_report_2202.pdf
-  atb_year: 2022
+  atb_year: 2025
+  cost_year: 2022 # to match ATB
 finance_parameters:
   general_inflation: 0.025 # based on 2022 ATB
   discount_rate: 0.10 # nominal return based on 2022 ATB basline workbook
@@ -42,21 +50,12 @@ finance_parameters:
     h2_transport_pipeline: 2018 # same model for costs as the h2_pipe_array
   wind:
     expected_plant_cost: 'none'
-    
 electrolyzer:
   rating: 180 # MW # 0.9*Plant rating appears near-optimal for 400 MW wind plant with 3 days of underground pipe storage # MW
   electrolyzer_capex: 700 # $/kW conservative 2025 centralized. high 700, low 300 # based on https://www.irena.org/-/media/Files/IRENA/Agency/Publication/2020/Dec/IRENA_Green_hydrogen_cost_2020.pdf
   time_between_replacement: 62320 # 62320 based on PEM Electrolysis H2A Production Case Study Documentation estimate of 7 years, 40000 based on current est (see unpublished report), 80000 hours based on OSW atb_year = 2025
   replacement_cost_percent: 0.15 # percent of capex - H2A default case
   model: "singlitico2021" # "basic" is a basic cost model based on H2a and HFTO program record for PEM electrolysis. "singlitico2021" uses cost estimates from that paper
-  
-# h2_transport_compressor:
-#   output_pressure: 100 # bar (1 bar = 100 kPa)
-#   flow_rate: 89 # kg/hr
-#   energy_rating: 802 # kWe (aka 1 kWh)
-#   mean_days_between_failures: 200 # days
-#   useful_life: 15 # was default in compressor script
-#   # annual_h2_throughput: 18750 # [kg/yr] -> kg of H2 per year
 h2_transport_compressor:
   outlet_pressure: 68 # bar based on HDSAM
 h2_storage_compressor:
@@ -142,65 +141,83 @@ plant_design:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario1:
     electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario2:
     electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario3:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario4:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario5:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario6:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario7:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario8:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc+pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario9:
+    electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
+    h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "onshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
+  scenario10:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     pv_location: "platform" # can be one of ["none", "onshore", "platform"]
-    battery_location: "none" # can be one of ["none", "onshore", "platform"]
-  scenario10:
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
+    battery_location: "platform" # can be one of ["none", "onshore", "platform"]
+  scenario11:
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     pv_location: "platform" # can be one of ["none", "onshore", "platform"]
-    battery_location: "platform" # can be one of ["none", "onshore", "platform"]
\ No newline at end of file
+    battery_location: "none" # can be one of ["none", "onshore", "platform"]
diff --git a/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config_onshore.yaml b/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config_onshore.yaml
index e474fcf8f..4fee33472 100644
--- a/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config_onshore.yaml
+++ b/tests/greenheart/test_hydrogen/input_files/plant/greenheart_config_onshore.yaml
@@ -1,9 +1,18 @@
 site:
   mean_windspeed: False 
+  depth: 45 #m
+  wind_layout:
+    row_spacing: 7  # Also defined in ORBIT config for offshore layout. Greenheart config values override the values in ORBIT.
+    turbine_spacing: 7 # Also defined in ORBIT config for offshore layout. Greenheart config values override the values in ORBIT.
+    grid_angle: 0 # wind layout grid angle in degrees where 0 is north, increasing clockwise
+    row_phase_offset: 0 # wind layout offset of turbines along row from one row to the next
 project_parameters:
+  project_lifetime: 30
   grid_connection: False # option, can be turned on or off
   ppa_price: 0.025 # $/kWh based on 2022 land based wind market report (ERCOT area ppa prices) https://www.energy.gov/sites/default/files/2022-08/land_based_wind_market_report_2202.pdf
-  atb_year: 2022
+  atb_year: 2025
+  cost_year: 2022 # to match ATB
+  installation_time: 36 # months
 finance_parameters:
   general_inflation: 0.025 # based on 2022 ATB
   discount_rate: 0.10 # nominal return based on 2022 ATB basline workbook
@@ -42,14 +51,12 @@ finance_parameters:
     h2_transport_pipeline: 2018 # same model for costs as the h2_pipe_array
   wind:
     expected_plant_cost: 'none'
-    
 electrolyzer:
   rating: 180 # MW # 0.9*Plant rating appears near-optimal for 400 MW wind plant with 3 days of underground pipe storage # MW
   electrolyzer_capex: 700 # $/kW conservative 2025 centralized. high 700, low 300 # based on https://www.irena.org/-/media/Files/IRENA/Agency/Publication/2020/Dec/IRENA_Green_hydrogen_cost_2020.pdf
   time_between_replacement: 62320 # 62320 based on PEM Electrolysis H2A Production Case Study Documentation estimate of 7 years, 40000 based on current est (see unpublished report), 80000 hours based on OSW atb_year = 2025
   replacement_cost_percent: 0.15 # percent of capex - H2A default case
   model: "singlitico2021" # "basic" is a basic cost model based on H2a and HFTO program record for PEM electrolysis. "singlitico2021" uses cost estimates from that paper
-
 h2_transport_compressor:
   outlet_pressure: 68 # bar based on HDSAM
 h2_storage_compressor:
@@ -110,61 +117,69 @@ plant_design:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario1:
     electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario2:
     electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario3:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario4:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario5:
     electrolyzer_location: "turbine" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario6:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "platform" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario7:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
     pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario8:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
     transportation: "hvdc+pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
-    pv_location: "none" # can be one of ["none", "onshore", "platform"]
-    battery_location: "none" # can be one of ["none", "onshore", "platform"]
+    wind_location: "offshore" # can be one of ["onshore", "offshore"]
   scenario9:
-    electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
-    transportation: "pipeline" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
+    electrolyzer_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
+    transportation: "none" # can be one of ["hvdc", "pipeline", "none", hvdc+pipeline]
     h2_storage_location: "onshore" # can be one of ["onshore", "turbine", "platform"]
-    pv_location: "platform" # can be one of ["none", "onshore", "platform"]
+    wind_location: "onshore" # can be one of ["onshore", "offshore"]
+    pv_location: "none" # can be one of ["none", "onshore", "platform"]
     battery_location: "none" # can be one of ["none", "onshore", "platform"]
   scenario10:
     electrolyzer_location: "platform" # can be one of ["onshore", "turbine", "platform"]
diff --git a/tests/greenheart/test_hydrogen/input_files/plant/hopp_config.yaml b/tests/greenheart/test_hydrogen/input_files/plant/hopp_config.yaml
index 68348ba1f..1641e75e4 100644
--- a/tests/greenheart/test_hydrogen/input_files/plant/hopp_config.yaml
+++ b/tests/greenheart/test_hydrogen/input_files/plant/hopp_config.yaml
@@ -7,14 +7,14 @@ site: #!include flatirons_site.yaml
     site_boundaries: 
       verts:  
         - [0.0, 0.0]
-        - [0.0, 2000.0]
-        - [2000.0, 2000.0]
-        - [2000.0, 0.0] 
+        - [0.0, 15000.0]
+        - [15000.0, 15000.0]
+        - [15000.0, 0.0] 
       verts_simple: 
         - [0.0, 0.0]
-        - [0.0, 2000.0]
-        - [2000.0, 2000.0]
-        - [2000.0, 0.0]
+        - [0.0, 15000.0]
+        - [15000.0, 15000.0]
+        - [15000.0, 0.0]
   solar_resource_file: ""
   wind_resource_file: "resource_files/wind/27.18624_-96.9516_windtoolkit_2013_60min_160m_200m.srw"
   wave_resource_file: ""
@@ -47,3 +47,4 @@ config:
     battery_dispatch: load_following_heuristic #heuristic
   cost_info:
     wind_installed_cost_mw: 3526000 # based on 2023 ATB moderate case for offshore wind
+    wind_om_per_kw: 104.271 # based on 2023 ATB moderate case for offshore wind
diff --git a/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW-stripped.yaml b/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW-stripped.yaml
index 8abb29767..ba2ac3759 100644
--- a/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW-stripped.yaml
+++ b/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW-stripped.yaml
@@ -1,20 +1,20 @@
 turbine: "osw_18MW"
-atb_year: 2025 # as per discussions of operational by 2027. This also makes the estimates a little more conservative
-cost_year: 2022 # to match ATB
+# atb_year: 2025 # as per discussions of operational by 2027. This also makes the estimates a little more conservative
+# cost_year: 2022 # to match ATB
 installation_availability: 0.7 # 30% downtime during installation to match ORCA
 site:
   area: 142 # km^2
-  depth: 45 # m
+  depth: 45 # m - this value is overridden by greenheart config
   distance: 80 # km
   distance_to_landfall: 85 # km
   mean_windspeed: False #8.45863584474886 # required input for ORBIT, provide desired mean wind speed or set to False to give ORBIT the mean wind speed from the lat/lon selection
 plant:
   capacity: 180 # MW
   layout: grid
-  num_turbines: 10 # needs to be changed based on turbine model
-  row_spacing: 7 # rotor diameters # based on rule of thumb of 7D
+  num_turbines: 10 # needs to be changed based on turbine model - this value is overridden by greenheart config
+  row_spacing: 7 # rotor diameters # based on rule of thumb of 7D - this value is overridden by greenheart config
   substation_distance: 1 # from ORBIT/examples/configs/example_fixed_project.yaml
-  turbine_spacing: 7 # rotor diameters # original 10
+  turbine_spacing: 7 # rotor diameters # original 10 - this value is overridden by greenheart config
 landfall:
   interconnection_distance: 5 # km
   trench_length: 4 # km
@@ -65,4 +65,4 @@ project_parameters:
   opex_rate: 97 # $USD/kW/yr ATB 2022, OpEx based on R&D assumptions with a base year of 2022.
   commissioning: 0.01 # ORBIT default
   decommissioning: 0.15 # ORBIT default
-  project_lifetime: 30 # 2022 ATB capital recovery period for offshore wind
\ No newline at end of file
+  # project_lifetime: 30 # 2022 ATB capital recovery period for offshore wind
\ No newline at end of file
diff --git a/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW.yaml b/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW.yaml
index 1ba4469c1..c58261108 100644
--- a/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW.yaml
+++ b/tests/greenheart/test_hydrogen/input_files/plant/orbit-config-osw_18MW.yaml
@@ -11,17 +11,17 @@ project_location: #
   lon: -96.9516 #
 site:
   area: 142 # km^2
-  depth: 45 # m
+  depth: 45 # m - this value is overridden by greenheart config
   distance: 80 # km
   distance_to_landfall: 85 # km
   mean_windspeed: False #8.45863584474886 # required input for ORBIT, provide desired mean wind speed or set to False to give ORBIT the mean wind speed from the lat/lon selection
 plant:
   capacity: 180 # MW
   layout: grid
-  num_turbines: 10 # needs to be changed based on turbine model
-  row_spacing: 7 # rotor diameters # based on rule of thumb of 7D
+  num_turbines: 10 # needs to be changed based on turbine model - this value is overridden by greenheart config
+  row_spacing: 7 # rotor diameters # based on rule of thumb of 7D - this value is overridden by greenheart config
   substation_distance: 1 # from ORBIT/examples/configs/example_fixed_project.yaml
-  turbine_spacing: 7 # rotor diameters # original 10
+  turbine_spacing: 7 # rotor diameters # original 10 - this value is overridden by greenheart config
 landfall:
   interconnection_distance: 5 # km
   trench_length: 4 # km
diff --git a/tests/greenheart/test_hydrogen/test_greenheart_system.py b/tests/greenheart/test_hydrogen/test_greenheart_system.py
index 47b590ba1..8183d06bb 100644
--- a/tests/greenheart/test_hydrogen/test_greenheart_system.py
+++ b/tests/greenheart/test_hydrogen/test_greenheart_system.py
@@ -1,17 +1,19 @@
-from re import S
-from greenheart.simulation.greenheart_simulation import run_simulation
-from pytest import approx
-
 import os
 
+from pytest import approx, warns
+import yaml
+from yamlinclude import YamlIncludeConstructor
+import warnings
+
+from greenheart.simulation.greenheart_simulation import (
+    run_simulation,
+    GreenHeartSimulationConfig,
+)
+
 from hopp.utilities.keys import set_nrel_key_dot_env
 
 set_nrel_key_dot_env()
 
-import yaml
-from yamlinclude import YamlIncludeConstructor
-
-from pathlib import Path
 from ORBIT.core.library import initialize_library
 
 dirname = os.path.dirname(__file__)
@@ -31,7 +33,7 @@
     orbit_library_path, f"turbines/{turbine_model}.yaml"
 )
 filename_orbit_config = os.path.join(
-    orbit_library_path, f"plant/orbit-config-{turbine_model}.yaml"
+    orbit_library_path, f"plant/orbit-config-{turbine_model}-stripped.yaml"
 )
 filename_floris_config = os.path.join(
     orbit_library_path, f"floris/floris_input_{turbine_model}.yaml"
@@ -43,12 +45,12 @@
 
 
 def test_simulation_wind(subtests):
-    lcoe, lcoh, _, hi = run_simulation(
-        filename_hopp_config,
-        filename_greenheart_config,
-        filename_turbine_config,
-        filename_orbit_config,
-        filename_floris_config,
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config=filename_hopp_config,
+        filename_greenheart_config=filename_greenheart_config,
+        filename_turbine_config=filename_turbine_config,
+        filename_orbit_config=filename_orbit_config,
+        filename_floris_config=filename_floris_config,
         verbose=False,
         show_plots=False,
         save_plots=False,
@@ -58,6 +60,7 @@ def test_simulation_wind(subtests):
         plant_design_scenario=1,
         output_level=5,
     )
+    lcoe, lcoh, _, hi = run_simulation(config)
 
     with subtests.test("lcoh"):
         assert lcoh == approx(
@@ -73,18 +76,37 @@ def test_simulation_wind(subtests):
         expected_annual_energy_hybrid = hi.system.annual_energies.wind
         assert hi.system.annual_energies.hybrid == approx(expected_annual_energy_hybrid)
 
+    with subtests.test("num_turbines conflict raise warning"):
+        config.orbit_config["plant"]["num_turbines"] = 400
+        with warns(UserWarning, match=f"The 'num_turbines' value"):
+            lcoe, lcoh, _, hi = run_simulation(config)
+    
+    with subtests.test("depth conflict raise warning"):
+        config.orbit_config["site"]["depth"] = 4000
+        with warns(UserWarning, match=f"The site depth value"):
+            lcoe, lcoh, _, hi = run_simulation(config)
+
+    with subtests.test("turbine_spacing conflict raise warning"):
+        config.orbit_config["plant"]["turbine_spacing"] = 400
+        with warns(UserWarning, match=f"The 'turbine_spacing' value"):
+            lcoe, lcoh, _, hi = run_simulation(config)
+
+    with subtests.test("row_spacing conflict raise warning"):
+        config.orbit_config["plant"]["row_spacing"] = 400
+        with warns(UserWarning, match=f"The 'row_spacing' value"):
+            lcoe, lcoh, _, hi = run_simulation(config)
 
 def test_simulation_wind_wave(subtests):
     filename_hopp_config_wind_wave = os.path.join(
         orbit_library_path, f"plant/hopp_config_wind_wave.yaml"
     )
 
-    lcoe, lcoh, _, hi = run_simulation(
-        filename_hopp_config_wind_wave,
-        filename_greenheart_config,
-        filename_turbine_config,
-        filename_orbit_config,
-        filename_floris_config,
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config=filename_hopp_config_wind_wave,
+        filename_greenheart_config=filename_greenheart_config,
+        filename_turbine_config=filename_turbine_config,
+        filename_orbit_config=filename_orbit_config,
+        filename_floris_config=filename_floris_config,
         verbose=False,
         show_plots=False,
         save_plots=False,
@@ -95,19 +117,15 @@ def test_simulation_wind_wave(subtests):
         output_level=5,
     )
 
+    lcoe, lcoh, _, hi = run_simulation(config)
+
     # TODO base this test value on something
     with subtests.test("lcoh"):
-        assert lcoh == approx(8.120065296802442)
+        assert lcoh == approx(8.133894926897252)
 
     # prior to 20240207 value was approx(0.11051228251811765) # TODO base this test value on something
     with subtests.test("lcoe"):
-        assert lcoe == approx(0.12863386719193057)
-
-    with subtests.test("energy sources"):
-        expected_annual_energy_hybrid = (
-            hi.system.annual_energies.wind + hi.system.annual_energies.wave
-        )
-        assert hi.system.annual_energies.hybrid == approx(expected_annual_energy_hybrid)
+        assert lcoe == approx(0.12887769358919945)
 
 
 def test_simulation_wind_wave_solar(subtests):
@@ -115,39 +133,33 @@ def test_simulation_wind_wave_solar(subtests):
         orbit_library_path, f"plant/hopp_config_wind_wave_solar.yaml"
     )
 
-    lcoe, lcoh, _, hi = run_simulation(
-        filename_hopp_config_wind_wave_solar,
-        filename_greenheart_config,
-        filename_turbine_config,
-        filename_orbit_config,
-        filename_floris_config,
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config=filename_hopp_config_wind_wave_solar,
+        filename_greenheart_config=filename_greenheart_config,
+        filename_turbine_config=filename_turbine_config,
+        filename_orbit_config=filename_orbit_config,
+        filename_floris_config=filename_floris_config,
         verbose=False,
         show_plots=False,
         save_plots=False,
         use_profast=True,
-        post_processing=False,
+        post_processing=True,
         incentive_option=1,
-        plant_design_scenario=9,
+        plant_design_scenario=11,
         output_level=5,
     )
 
+    lcoe, lcoh, _, hi = run_simulation(config)
+
     # prior to 20240207 value was approx(10.823798551850347)
     # TODO base this test value on something. Currently just based on output at writing.
     with subtests.test("lcoh"):
-        assert lcoh == approx(12.583155204831298)
+        assert lcoh == approx(12.597232748295273)
 
     # prior to 20240207 value was approx(0.11035426429749774)
     # TODO base this test value on something. Currently just based on output at writing.
     with subtests.test("lcoe"):
-        assert lcoe == approx(0.1284376127848134)
-
-    with subtests.test("energy sources"):
-        expected_annual_energy_hybrid = (
-            hi.system.annual_energies.wind
-            + hi.system.annual_energies.wave
-            + hi.system.annual_energies.pv
-        )
-        assert hi.system.annual_energies.hybrid == approx(expected_annual_energy_hybrid)
+        assert lcoe == approx(0.12868090262684384)
 
 
 def test_simulation_wind_wave_solar_battery(subtests):
@@ -155,33 +167,32 @@ def test_simulation_wind_wave_solar_battery(subtests):
         orbit_library_path, f"plant/hopp_config_wind_wave_solar_battery.yaml"
     )
 
-    lcoe, lcoh, _, hi = run_simulation(
-        filename_hopp_config_wind_wave_solar_battery,
-        filename_greenheart_config,
-        filename_turbine_config,
-        filename_orbit_config,
-        filename_floris_config,
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config=filename_hopp_config_wind_wave_solar_battery,
+        filename_greenheart_config=filename_greenheart_config,
+        filename_turbine_config=filename_turbine_config,
+        filename_orbit_config=filename_orbit_config,
+        filename_floris_config=filename_floris_config,
         verbose=False,
         show_plots=False,
         save_plots=False,
         use_profast=True,
-        post_processing=False,
+        post_processing=True,
         incentive_option=1,
         plant_design_scenario=10,
         output_level=5,
     )
 
-    # TODO base this test value on something. Currently just based on output at writing.
+    lcoe, lcoh, _, hi = run_simulation(config)
+
     with subtests.test("lcoh"):
-        assert lcoh == approx(16.96997513319437)
+        # TODO base this test value on something. Currently just based on output at writing.
+        assert lcoh == approx(16.984071652636903)
 
     # TODO base this test value on something. Currently just based on output at writing.
     with subtests.test("lcoe"):
-        assert lcoe == approx(0.12912145788428933)
-
-    # with subtests.test("energy sources"): # TODO why is hybrid energy different than the sum of the parts when battery is being used.
-    #     expected_annual_energy_hybrid = hi.system.annual_energies.wind + hi.system.annual_energies.wave + hi.system.annual_energies.pv
-    #     assert hi.system.annual_energies.hybrid == expected_annual_energy_hybrid
+        # TODO base this test value on something. Currently just based on output at writing.
+        assert lcoe == approx(0.12936583137325117)  
 
 
 def test_simulation_wind_onshore(subtests):
@@ -189,81 +200,84 @@ def test_simulation_wind_onshore(subtests):
         orbit_library_path, f"plant/greenheart_config_onshore.yaml"
     )
 
-    lcoe, lcoh, _, _ = run_simulation(
-        filename_hopp_config,
-        filename_greenheart_config_onshore,
-        filename_turbine_config,
-        filename_orbit_config,
-        filename_floris_config,
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config=filename_hopp_config,
+        filename_greenheart_config=filename_greenheart_config_onshore,
+        filename_turbine_config=filename_turbine_config,
+        filename_orbit_config=filename_orbit_config,
+        filename_floris_config=filename_floris_config,
         verbose=False,
         show_plots=False,
         save_plots=False,
         use_profast=True,
         post_processing=False,
         incentive_option=1,
-        plant_design_scenario=1,
+        plant_design_scenario=9,
         output_level=5,
     )
+    # based on 2023 ATB moderate case for onshore wind
+    config.hopp_config["config"]["cost_info"]["wind_installed_cost_mw"] = 1434000.0 
+    # based on 2023 ATB moderate case for onshore wind
+    config.hopp_config["config"]["cost_info"]["wind_om_per_kw"] = 29.567
+    # set skip_financial to false for onshore wind
+    config.hopp_config["config"]["simulation_options"]["wind"]["skip_financial"] = False
+
+    lcoe, lcoh, _, _ = run_simulation(config)
 
+    # TODO base this test value on something
     with subtests.test("lcoh"):
-        assert lcoh == approx(
-            7.057994298481547
-        )  # TODO base this test value on something
+        assert lcoh == approx(3.040736244214041)  
 
+    # TODO base this test value on something
     with subtests.test("lcoe"):
-        assert lcoe == approx(
-            0.10816180445700445
-        )  # TODO base this test value on something
+        assert lcoe == approx(0.034869608896094494)
 
 
 def test_simulation_wind_onshore_steel_ammonia(subtests):
-    turbine_model = "osw_18MW"
-    filename_turbine_config = os.path.join(
-        orbit_library_path, f"turbines/{turbine_model}.yaml"
-    )
-    filename_orbit_config = os.path.join(
-        orbit_library_path, f"plant/orbit-config-{turbine_model}.yaml"
-    )
-    filename_floris_config = os.path.join(
-        orbit_library_path, f"floris/floris_input_{turbine_model}.yaml"
-    )
     filename_greenheart_config = os.path.join(
         orbit_library_path, f"plant/greenheart_config_onshore.yaml"
     )
-    filename_hopp_config = os.path.join(orbit_library_path, f"plant/hopp_config.yaml")
-
-    lcoe, lcoh, steel_finance, ammonia_finance = run_simulation(
-        filename_hopp_config,
-        filename_greenheart_config,
-        filename_turbine_config,
-        filename_orbit_config,
-        filename_floris_config,
+
+    config = GreenHeartSimulationConfig(
+        filename_hopp_config=filename_hopp_config,
+        filename_greenheart_config=filename_greenheart_config,
+        filename_turbine_config=filename_turbine_config,
+        filename_orbit_config=filename_orbit_config,
+        filename_floris_config=filename_floris_config,
         verbose=False,
         show_plots=False,
         save_plots=False,
         use_profast=True,
         post_processing=False,
         incentive_option=1,
-        plant_design_scenario=1,
+        plant_design_scenario=9,
         output_level=7,
     )
+    # based on 2023 ATB moderate case for onshore wind
+    config.hopp_config["config"]["cost_info"]["wind_installed_cost_mw"] = 1434000.0 
+    # based on 2023 ATB moderate case for onshore wind
+    config.hopp_config["config"]["cost_info"]["wind_om_per_kw"] = 29.567
+    config.hopp_config["technologies"]["wind"]["fin_model"]["system_costs"]["om_fixed"][0] = config.hopp_config["config"]["cost_info"]["wind_om_per_kw"]
+    # set skip_financial to false for onshore wind
+    config.hopp_config["config"]["simulation_options"]["wind"]["skip_financial"] = False
+    lcoe, lcoh, steel_finance, ammonia_finance = run_simulation(config)
 
+    # TODO base this test value on something
     with subtests.test("lcoh"):
-        assert lcoh == approx(
-            7.057994298481547
-        )  # TODO base this test value on something
+        assert lcoh == approx(3.040736244214041)
 
+    # TODO base this test value on something
     with subtests.test("lcoe"):
-        assert lcoe == approx(
-            0.10816180445700445
-        )  # TODO base this test value on something
+        assert lcoe == approx(0.034869649135212274)
 
+    # TODO base this test value on something
     with subtests.test("steel_finance"):
-        lcos_expected = 1626.5484389152123
+        lcos_expected = 1348.5863267221866
 
         assert steel_finance.sol.get("price") == approx(lcos_expected)
 
+    # TODO base this test value on something
     with subtests.test("ammonia_finance"):
-        lcoa_expected = 1.0441398120394485
+        lcoa_expected = 1.0419316870652462
 
         assert ammonia_finance.sol.get("price") == approx(lcoa_expected)