Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a771e32
Merge pull request #169 from WISDEM/release-2.3.4
akey7 Dec 28, 2020
3e22372
Merge pull request #171 from WISDEM/release-2.3.5
akey7 Feb 9, 2021
82c74e3
Merge pull request #176 from WISDEM/release-2.4.0
akey7 Aug 9, 2021
1920f8e
Merge pull request #178 from WISDEM/release-2.4.1
akey7 Feb 7, 2022
6575457
Merge pull request #190 from WISDEM/develop
gbarter Jun 19, 2023
61c1770
Merge pull request #192 from WISDEM/develop
gbarter Jan 24, 2024
68dbb5a
reformat & fix repeated pd.concats
crookp Aug 16, 2024
664cb44
Update LICENSE.txt
eberlea Aug 20, 2024
14f7917
allow calling from other modules
crookp Aug 22, 2024
a79fc19
autoformat CollectionCost.py
crookp Dec 9, 2024
8d0db0a
handle zeroes in num_turbines_per_cable without printing
crookp Dec 9, 2024
49ec186
remove outputs
crookp Dec 9, 2024
91c29fd
include missing pi in volume calculation
crookp Dec 9, 2024
c521755
add landbosse_runner.py
crookp Dec 16, 2024
e948877
correct inductance and capacitance units
crookp Dec 16, 2024
2271590
move check for required inputs to initialization rather than before r…
crookp Dec 17, 2024
e2a04ca
Retain keys in input dict when extracting configs
crookp Jan 17, 2025
17a20e7
Add check for required weather data columns
crookp Jan 17, 2025
6e61182
Clarify requirements for management cost argument
crookp Jan 17, 2025
2195287
add turbine cost calculation (based on simple capex)
crookp Jan 24, 2025
e81c511
Add turbine Capex (#196)
crookp Jan 27, 2025
21aca8f
Revert "Add turbine Capex (#196)"
crookp Jan 27, 2025
94d4387
Merge branch 'WISDEM:master' into add_turbine_cost
crookp Jan 27, 2025
fdbca14
Merge branch 'develop' into add_turbine_cost
crookp Jan 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2018 NREL
Copyright 2018 Alliance for Sustainable Energy, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -10,4 +10,4 @@ Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
Binary file added input/project_list.xlsx
Binary file not shown.
1 change: 1 addition & 0 deletions landbosse/excelio/XlsxReader.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ def create_master_input_dictionary(self, project_data_dataframes, project_parame
incomplete_input_dict['bearing_pressure_n_m2'] = project_parameters['Bearing Pressure (n/m2)']
incomplete_input_dict['gust_velocity_m_per_s'] = project_parameters['50-year Gust Velocity (m/s)']
incomplete_input_dict['project_size_megawatts'] = project_parameters['Number of turbines'] * project_parameters['Turbine rating MW']
incomplete_input_dict['turbine_capex'] = project_parameters.get('Turbine Capex (USD/kW)', 0.0)

if project_parameters['Calculate road cost for distributed wind? (y/n)'] == 'y':
incomplete_input_dict['road_distributed_wind'] = True
Expand Down
4 changes: 3 additions & 1 deletion landbosse/landbosse_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class LandBOSSERunner:
"diameters",
"row_spacing_rotor_diameter": "Layout spacing between rows, in rotor diameters",
"num_turbines": "Number of turbines",
"turbine_capex": "CapEx of turbine ($/kW)",
"base_topping_breakpoint": "Height at which cranes change from 'Base' to 'Topping', "
"represented as a fraction of hub height",
"fuel_cost_usd_per_gal": "Cost of fuel per gallon ($/gal)",
Expand Down Expand Up @@ -113,7 +114,7 @@ class LandBOSSERunner:
"surface_area_m2": "List of tower section surface areas (m^2), from bottom to top. "
"Must be the same legnth as the other tower section attributes",
"height_m": "List of tower section heights (m), from bottom to top. Must be the "
"same legnth as the other tower section attributes",
"same length as the other tower section attributes",
},
},
}
Expand All @@ -129,6 +130,7 @@ class LandBOSSERunner:
"turbine_spacing_rotor_diameter": "Turbine spacing (times rotor diameter)",
"row_spacing_rotor_diameter": "Row spacing (times rotor diameter)",
"num_turbines": "Number of turbines",
"turbine_capex": "Turbine Capex (USD/kW)",
"base_topping_breakpoint": "Breakpoint between base and topping (percent)",
"fuel_cost_usd_per_gal": "Fuel cost USD per gal",
"turbine_delivery_rate_per_week": "Rate of deliveries (turbines per week)",
Expand Down
8 changes: 8 additions & 0 deletions landbosse/model/Manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .FoundationCost import FoundationCost
from .SubstationCost import SubstationCost
from .TransportCost import TransportCost
from .TurbineCost import TurbineCost
from .GridConnectionCost import GridConnectionCost
from .SitePreparationCost import SitePreparationCost
from .CollectionCost import ArraySystem
Expand Down Expand Up @@ -72,6 +73,13 @@ def execute_landbosse(self, project_name):
project_name=project_name)
development_cost.run_module()

turbine_cost = TurbineCost(
input_dict=self.input_dict,
output_dict=self.output_dict,
project_name=project_name,
)
turbine_cost.run_module()

erection_cost_output_dict = dict()
erection_cost = ErectionCost(
input_dict=self.input_dict,
Expand Down
135 changes: 135 additions & 0 deletions landbosse/model/TurbineCost.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
from .CostModule import CostModule

import traceback
import numpy as np
import pandas as pd

class TurbineCost(CostModule):
"""
**TurbineCost.py**

Calculates the CapEx cost of the turbine itself

This is a simple feedthrough calculation that requires an input CapEx assumption ($/kW)

The structure of this class contains many superfluous elements, but it has been made to match
the other LandBOSSE cost modules

turbine_capex
(float) CapEx cost of turbine ($/kW)

number_turbines
(int) Number of turbines
"""

def __init__(self, input_dict, output_dict, project_name):
"""
Parameters
----------
input_dict : dict
The input dictionary with key value pairs described in the
class documentation

output_dict : dict
The output dictionary with key value pairs as found on the
output documentation.
"""
self.input_dict = input_dict
self.output_dict = output_dict
self.project_name = project_name

def calculate_costs(self, calculate_costs_input_dict , calculate_costs_output_dict):
"""
Function to calculate turbine cost in USD

Parameters
-------
turbine_capex
(in $/kW, default $1500/kW)

number_turbines
(unitless)

Returns:
-------
turbine_cost
(in USD)

"""

turbine_capex = calculate_costs_input_dict["turbine_capex"]
if np.isnan(turbine_capex):
turbine_capex = 0.0

num_turbines = calculate_costs_input_dict["num_turbines"]
turbine_rating_kW = calculate_costs_input_dict["turbine_rating_MW"] * 1000

turbine_cost = turbine_capex * num_turbines * turbine_rating_kW

calculate_costs_output_dict["turbine_cost"] = turbine_cost

calculate_costs_output_dict["turbine_cost_output_df"] = pd.DataFrame(
[["Other", calculate_costs_output_dict["turbine_cost"], "Turbine"]],
columns=["Type of cost", "Cost USD", "Phase of construction"],
)


def outputs_for_detailed_tab(self, input_dict, output_dict):
"""
Creates a list of dictionaries which can be used on their own or
used to make a dataframe.

Must be called after self.run_module()

Returns
-------
list(dict)
A list of dicts, with each dict representing a row of the data.
"""

result = []
module = type(self).__name__

result.append({
"unit": "usd",
"type": "variable",
"variable_df_key_col_name": "Turbine CapEx",
"value": float(self.output_dict["turbine_cost"]),
})

for _dict in result:
_dict["project_id_with_serial"] = self.project_name
_dict["module"] = module

self.output_dict["turbine_cost_csv"] = result

def run_module(self):
"""
Runs the TurbineCost module and populates the IO dictionaries with calculated values.

Parameters
----------
<None>

Returns
-------
tuple
First element of tuple contains a 0 or 1. 0 means no errors happened and
1 means an error happened and the module failed to run. The second element
either returns a 0 if the module ran successfully, or it returns the error
raised that caused the failure.

"""
try:
self.calculate_costs(self.input_dict, self.output_dict)
self.outputs_for_detailed_tab(self.input_dict, self.output_dict)
self.output_dict["turbine_module_type_operation"] = self.outputs_for_costs_by_module_type_operation(
input_df=self.output_dict["turbine_cost_output_df"],
project_id=self.project_name,
total_or_turbine=True
)
return 0, 0
except Exception as error:
traceback.print_exc()
print(f"Fail {self.project_name} TurbineCost")
return 1, error
Loading