From b7c1dc32eb53a463165a78eaf9b9bf25ba2ca96f Mon Sep 17 00:00:00 2001 From: Garrett Barter Date: Fri, 28 Feb 2025 10:52:19 -0700 Subject: [PATCH 1/6] syncing with new orbit approach to commissioning and decommissioning --- .../landbosse_omdao/OpenMDAODataframeCache.py | 1 + landbosse/landbosse_omdao/landbosse.py | 30 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/landbosse/landbosse_omdao/OpenMDAODataframeCache.py b/landbosse/landbosse_omdao/OpenMDAODataframeCache.py index 46632834..06c9df73 100644 --- a/landbosse/landbosse_omdao/OpenMDAODataframeCache.py +++ b/landbosse/landbosse_omdao/OpenMDAODataframeCache.py @@ -87,6 +87,7 @@ def read_all_sheets_from_xlsx(cls, xlsx_basename, xlsx_path=None): for sheet_name in xlsx.sheet_names: sheets_dict[sheet_name].dropna(inplace=True, how='all') cls._cache[xlsx_basename] = sheets_dict + xlsx.close() return cls.copy_dataframes(sheets_dict) @classmethod diff --git a/landbosse/landbosse_omdao/landbosse.py b/landbosse/landbosse_omdao/landbosse.py index 3f5518f6..834901a0 100644 --- a/landbosse/landbosse_omdao/landbosse.py +++ b/landbosse/landbosse_omdao/landbosse.py @@ -31,8 +31,8 @@ def setup(self): self.set_input_defaults("turbine_spacing_rotor_diameters", 4) self.set_input_defaults("row_spacing_rotor_diameters", 10) - self.set_input_defaults("commissioning_pct", 0.01) - self.set_input_defaults("decommissioning_pct", 0.15) + self.set_input_defaults("commissioning_cost_kW", 44.0, units="USD/kW") + self.set_input_defaults("decommissioning_cost_kW", 58.0, units="USD/kW") self.set_input_defaults("trench_len_to_substation_km", 50.0, units="km") self.set_input_defaults("interconnect_voltage_kV", 130.0, units="kV") @@ -42,7 +42,7 @@ def setup(self): self.set_input_defaults("nacelle_mass", 50e3, units="kg") self.set_input_defaults("tower_mass", 240e3, units="kg") self.set_input_defaults("turbine_rating_MW", 1500.0, units="kW") - self.set_input_defaults("turbine_capex", 0.0, units="USD/kW") + self.set_input_defaults("turbine_capex_kW", 0.0, units="USD/kW") self.add_subsystem("landbosse", LandBOSSE_API(), promotes=["*"]) @@ -102,6 +102,7 @@ def setup_inputs(self): self.add_input("hub_height_meters", val=80, units="m", desc="Hub height m") self.add_input("rotor_diameter_m", val=77, units="m", desc="Rotor diameter m") self.add_input("wind_shear_exponent", val=0.2, desc="Wind shear exponent") + self.add_input("turbine_capex_kW", val=0.0, units="USD/kW", desc="Turbine capital cost") self.add_input("turbine_rating_MW", val=1.5, units="MW", desc="Turbine rating MW") self.add_input("fuel_cost_usd_per_gal", val=1.5, desc="Fuel cost USD/gal") @@ -164,9 +165,8 @@ def setup_inputs(self): # Disabled due to Pandas conflict right now. self.add_input("labor_cost_multiplier", val=1.0, desc="Labor cost multiplier") - self.add_input("commissioning_pct", 0.01) - self.add_input("decommissioning_pct", 0.15) - self.add_input("turbine_capex", 0.0, units="USD/kW") + self.add_input("commissioning_cost_kW", 44.0, units="USD/kW", desc="Commissioning cost.") + self.add_input("decommissioning_cost_kW", 58.0, units="USD/kW", desc="Decommissioning cost.") def setup_discrete_inputs_that_are_not_dataframes(self): """ @@ -450,6 +450,9 @@ def prepare_master_input_dictionary(self, inputs, discrete_inputs): discrete_inputs["num_turbines"] * inputs["turbine_rating_MW"][0] ) + # Turbine Capex + incomplete_input_dict["turbine_capex"] = float(inputs["turbine_capex_kW"][0]) + # Needed to avoid distributed wind keys incomplete_input_dict["road_distributed_wind"] = False @@ -586,24 +589,23 @@ def compute_total_bos_costs(self, costs_by_module_type_operation, master_output_ installation_per_kW = 0.0 for row in costs_by_module_type_operation: + if row["Module"] in ["TurbineCost"]: + continue bos_per_kw += row["Cost / kW"] bos_per_project += row["Cost / project"] if row["Module"] in ["ErectionCost", "FoundationCost"]: installation_per_project += row["Cost / project"] installation_per_kW += row["Cost / kW"] - commissioning_pct = inputs["commissioning_pct"] - decommissioning_pct = inputs["decommissioning_pct"] + commissioning_kW = inputs["commissioning_cost_kW"] + decommissioning_kW = inputs["decommissioning_cost_kW"] - commissioning_per_project = bos_per_project * commissioning_pct - decomissioning_per_project = bos_per_project * decommissioning_pct - commissioning_per_kW = bos_per_kw * commissioning_pct - decomissioning_per_kW = bos_per_kw * decommissioning_pct + capacity = bos_per_project / bos_per_kw - outputs["total_capex_kW"] = bos_per_kw + commissioning_per_kW + decomissioning_per_kW - outputs["total_capex"] = bos_per_project + commissioning_per_project + decomissioning_per_project outputs["bos_capex"] = bos_per_project outputs["bos_capex_kW"] = bos_per_kw + outputs["total_capex_kW"] = bos_per_kw + commissioning_kW + decommissioning_kW + outputs["total_capex"] = bos_per_project + capacity*(commissioning_kW + decommissioning_kW) outputs["installation_capex"] = installation_per_project outputs["installation_capex_kW"] = installation_per_kW From 93a8ca366b5d7b4ef566f7d45ae605045d7fa79a Mon Sep 17 00:00:00 2001 From: Garrett Barter Date: Tue, 6 May 2025 08:45:57 -0600 Subject: [PATCH 2/6] adding weto stack in readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index b802f824..fb67479e 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,16 @@ Eberle, Annika, Owen Roberts, Alicia Key, Parangat Bhaskar, and Katherine Dykes. National Renewable Energy Laboratory. NREL/TP-6A20-72201. https://www.nrel.gov/docs/fy19osti/72201.pdf. + +## Part of the WETO Stack + +LandBOSSE is primarily developed with the support of the U.S. Department of Energy and is part of the [WETO Software Stack](https://nrel.github.io/WETOStack). For more information and other integrated modeling software, see: +- [Portfolio Overview](https://nrel.github.io/WETOStack/portfolio_analysis/overview.html) +- [Entry Guide](https://nrel.github.io/WETOStack/_static/entry_guide/index.html) +- [Techno-Economic Modeling Workshop](https://nrel.github.io/WETOStack/workshops/user_workshops_2024.html#tea-and-cost-modeling) +- [Systems Engineering Workshop](https://nrel.github.io/WETOStack/workshops/user_workshops_2024.html#systems-engineering) + + ## User Guides First, read the technical report to understand the big picture of LandBOSSE. In the technical report, you will find process diagrams, equations and the modules that implement them. Then, come back to this documentation and read the user guide. From ae18723143240d70fdcd77034620338ed991a1f6 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Mon, 9 Mar 2026 12:48:43 -0700 Subject: [PATCH 3/6] Docs: Create a Comprehensive User Guide (#203) * fix extra lines between bullet list * start framework for user guide * add table mapping between landbosser input categories * fix broken runner code * remove dictionary component handling in place of existing excel data * update changelog * fix typo * update excel data sections * fix typo * use definition lists to provide more contextual information for each of the data columns * add run instructions * add developer guide * add develop option * add missing column to and create an Excel-dictionary converter * add further data context and an example of converting the data * update changelog * update readme --- CHANGELOG.md | 14 + README.md | 30 +- docs/_config.yml | 10 + docs/_toc.yml | 2 +- docs/contributing.md | 43 +- docs/example.md | 679 ++++++++++++++++++++++++++++++ docs/examples.md | 3 - landbosse/excelio/XlsxReader.py | 11 - landbosse/landbosse_runner.py | 176 +++----- landbosse/model/ErectionCost.py | 2 +- landbosse/model/FoundationCost.py | 2 +- pyproject.toml | 1 + 12 files changed, 812 insertions(+), 161 deletions(-) create mode 100644 docs/example.md delete mode 100644 docs/examples.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d12f1d7..4820278b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # LandBOSSE Changelog +## Unreleased + ++ Corrects an error in multiple names defined for `LandBOSSERunner`s data connection to project + Excel file, which is now called "data_tables", consistent with the implementation made in + the `WAVES` integration. ++ Removes the reliance on `component` data being provided outside the Excel project data to reduce + duplicated data definitions. ++ Corrects the `LandBOSSERunner.keys_rename` to ensure all required variables are included. ++ Makes the `weather` input to `LandBOSSERunner` optional, so that the Excel "weather_window" sheet + will still be used if provided. If `weather` is provided as an input, it will override the the + Excel-defined "weather_window" sheet. ++ `LandBOSSERunner.convert_excel_to_dict()` added for converting a project from an Excel-based + project list to a compatible dictionary. + ## 2.6.2 (February 26, 2026) + Docstrings are reformatted to display nicely on a Jupyter Book documentation site. diff --git a/README.md b/README.md index 010fa330..9ba1c559 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,9 @@ LandBOSSE is primarily developed with the support of the U.S. Department of Ener - [Techno-Economic Modeling Workshop](https://nrel.github.io/WETOStack/workshops/user_workshops_2024.html#tea-and-cost-modeling) - [Systems Engineering Workshop](https://nrel.github.io/WETOStack/workshops/user_workshops_2024.html#systems-engineering) -## User Guides +## User Guide + +### Installation For any installation, users should use a virtual environment. We recommend Miniconda or Anaconda, but any supporting PyPI or source installations are possible. Here, we'll work with conda for @@ -37,13 +39,13 @@ can be any that you prefer as long as it's supported by LandBOSSE. conda create -n landbosse python=3.13 -y ``` -### PyPI +#### PyPI ```bash pip install NREL-landbosse ``` -### Source +#### Source 1. Navigate to your preferred installation location 2. Clone the repo (or fork and clone your fork, if preferred). @@ -61,9 +63,7 @@ pip install NREL-landbosse Optional: `pip install -e .` for editable installations if you plan to modify the code itself. -## User Guides - -### First time running teh model +### First time running the model At its most basic, the following setup is required, though the provided input data in `project_inpute_template` can be used to test out the model and view results before diving into configuring custom scenarios. @@ -75,8 +75,7 @@ can be used to test out the model and view results before diving into configurin 3. Each project in `project_list.xlsx` should have a corresponding Excel file in `project_data` similar to the examples in `LandBOSSE/project_input_template/project_data`. - -### Running the model +### Running the model Once the initial steps (above) are followed, we can run the model: @@ -85,18 +84,17 @@ Once the initial steps (above) are followed, we can run the model: 3. Run the model: `python main.py -i input-folder-path -o output-folder-path` (be sure to replace "input-folder-path" and "output-folder-path" with your respective input and output folders). -All together + All together, this is: -```bash -conda activate landbosse -cd /path/to/LandBOSSE -python main.py -i /path/to/inputs -o /path/to/outputs -conda deactivate -``` + ```bash + conda activate landbosse + cd /path/to/LandBOSSE + python main.py -i /path/to/inputs -o /path/to/outputs + conda deactivate + ``` 4. View your results in the output folder. - ### Integrating LandBOSSE into your code While LandBOSSE was originally designed as a CLI tool powered by Excel workbooks, an API also exists diff --git a/docs/_config.yml b/docs/_config.yml index fe2d496f..0630f8cd 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -30,6 +30,16 @@ repository: html: use_issues_button: true use_repository_button: true + home_page_in_navbar: true + +parse: + myst_url_schemes: [mailto, http, https] + myst_enable_extensions: + - dollarmath + - amsmath + - deflist + - linkify + - colon_fence sphinx: extra_extensions: diff --git a/docs/_toc.yml b/docs/_toc.yml index 2004a87b..c2942f7e 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -5,5 +5,5 @@ format: jb-book root: intro chapters: - file: api -- file: examples +- file: example - file: contributing \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md index 3302eb19..1d8f2ed4 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,3 +1,42 @@ -# Contributor's Guide +# Developer's Guide -Coming soon. \ No newline at end of file +## Installation + +1. Navigate to your preferred installation location +2. Fork LandBOSSE +3. Clone your fork + + ```bash + git clone https://github.com//LandBOSSE.git + ``` + +4. Enter the directory and locally install an editable version with the testing and documentation + building dependencies. + + ```bash + cd LandBOSSE + pip install -e .[test, docs] + ``` + +## Testing the Code + +Run LandBOSSE's testing suite using the following command. Please note the tests are not +particularly robust at this time, so passing tests after modifying the codeshould be viewed with +caution. + +```bash +pytest landbosse +``` + +## Building the documentation + +LandBOSSE uses Jupyter Book (v1) for its documentation site, which can be recreated locally with +the following command from the top-level directory. + +```bash +jupyter book build docs/ +``` + +Once complete, there will be a callout to "paste this line directly into your browser bar" with the +next line in the form of `file:///path/to/LandBOSSE/docs/_build/html/index.html`, which should be +pasted into the browser bar like a URL. You should now be able to peruse the documentation. diff --git a/docs/example.md b/docs/example.md new file mode 100644 index 00000000..e6c525ac --- /dev/null +++ b/docs/example.md @@ -0,0 +1,679 @@ +# User Guide + +This example will work with the `project_input_template/project_list_simplified.xlsx`, which +includes the GE 1.5 MW validation example (`project_input_template/project_data/ge15_public.xlsx`). +Using these data, we will walk through the setup of the project-specific data, project listings, +and running the model. + +## Project Input Data + +LandBOSSE relies on the use of separate input and output folders. For any set of projects, these +can be defined as environment variables using the names `LANDBOSSE_INPUT_DIR` and +`LANDBOSSE_OUTPUT_DIR`, or provided when running the code (more details in [Running LandBOSSE](#running-landbosse)). + +An example of a project input folder is provided with the code: the folder `project_input_template/` +where listings of projects can be stored and the subfolder `project_data` where all project-specific +Excel files are stored. + +### Project listing and the `LandBOSSERunner` API + +As stated in the introduction, we'll be working with `project_list_simplified.xlsx` which contains +a single project (unlike `project_list.xlsx` which runs several projects simultaneously), the +public-facing GE 1.5 MW example (`ge15_public.xlsx`). + +The below table explains each of the expected parameters found when setting up either the +`project_list.xlsx` or the `LandBOSSERunner` input dictionary. For Excel setups, each row in +"Project List Column" represents a column name in the project list Excel file. Using the Excel setup, +we can run multiple projects, though this example relies models a single project. Similarly, using +the `LandBOSSERunner` configuration dictionary, each row in "LandBOSSE Runner Key" represents a +dictionary key. Notably, using the `LandBOSSERunner` API enables single project runs only. In both +cases the "Description" column describes what data are expected as an Excel sheet's cell value or +dictionary key's value. + +| Project List Column | LandBOSSE Runner Key | Description | +| -------------------------------------------------------------------- | ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| Project ID | id | Name of the project | +| Project data file | data_tables | Excel filename associated with the project | +| Total project construction time (months) | construction_months | Total construction duration (months) | +| Turbine rating MW | turbine_rating_MW | Capacity of turbine (MW) | +| Hub height m | hub_height_m | Turbine hub height (m) | +| Rotor diameter m | rotor_diameter_m | Turbine rotor diameter (m) | +| Turbine spacing (times rotor diameter) | turbine_spacing_rotor_diameter | Layout spacing between turbines in each row, in rotor diameters | +| Row spacing (times rotor diameter) | row_spacing_rotor_diameter | Layout spacing between rows, in rotor diameters | +| Number of turbines | num_turbines | Number of turbines | +| Turbine Capex (USD/kW) | turbine_capex | CapEx of turbine ($/kW) | +| Breakpoint between base and topping (percent) | base_topping_breakpoint | Height at which cranes change from 'Base' to 'Topping', represented as a fraction of hub height | +| Fuel cost USD per gal | fuel_cost_usd_per_gal | Cost of fuel per gallon ($/gal) | +| Rate of deliveries (turbines per week) | turbine_delivery_rate_per_week | Number of turbine deliveries (all components) per week | +| Wind shear exponent | wind_shear | Wind shear (assumed constant across all timestamps and turbines) | +| Foundation depth m | foundation_depth_m | Depth of concrete foundation (m) | +| Rated Thrust (N) | rated_thrust_N | Rated horizontal thrust of turbine (N) | +| Bearing Pressure (n/m2) | bearing_pressure_Pa | Bearing pressure capacity of soil underneath foundations (Pa) | +| 50-year Gust Velocity (m/s) | gust_velocity_50_year_m/s | 50 year wind gust velocity (m/s) | +| Line Frequency (Hz) | line_frequency | Electrical frequency of grid (Hz) | +| Combined homerun trench length to substation (km) | combined_homerun_trench_length_km | Combined homerun trench length to substation (km) (optional - can be null but cannot be omitted) | +| Flag for user-defined home run trench length (0 = no; 1 = yes) | user_trench_length_flag | Flag (0 = no; 1 = yes) to indicate if the user-defined trench length should be used | +| Non-Erection Wind Delay Critical Height (m) | non_erection_wind_delay_critical_height_m | When calculating wind delays for non-erection tasks, shear values to this height (m) | +| Non-Erection Wind Delay Critical Speed (m/s) | non_erection_wind_delay_critical_wind_speed_m/s | When calculating wind delays for non-erection tasks, wind speeds above this value will force work to stop (m/s) | +| Distance to interconnect (miles) | distance_to_interconnect_mi | Distance from substation to switchyard (miles) | +| Interconnect Voltage (kV) | interconnect_voltage_kV | Voltage of grid (kV) | +| New Switchyard (y/n) | new_switchyard | Should a new switchyard be built (true/false) | +| Road length adder (m) | road_length_adder_m | Distance from site entry point to the project (m) | +| Road Quality (0-1) | road_quality | Non-dimensional representation of the quality of roads. 0 is poor quality, 1 is good quality. A higher road quality reduces the total road cost | +| Percent of roads that will be constructed | percent_roads_to_be_constructed | What percentage of roads need to be constructed vs already exist | +| Road width (ft) | road_width_ft | Width of roads (ft) | +| Road thickness (in) | road_thickness_in | Thickness of roads (in) | +| Calculate road cost for distributed wind? (y/n) | calculate_road_cost_for_distributed_wind | Should road costs be included in the calculation for distributed wind projects (true/false) | +| Site prep area for Distributed wind (m2) | site_prep_area_for_distributed_wind_m2 | Site prep area for distributed wind projects (m^2) | +| Crane width (m) | crane_width_m | Width of crane (m) | +| Number of highway permits | num_highway_permits | Number of highway permits required | +| Number of access roads | num_access_roads | Number of site access roads required | +| Overtime multiplier | overtime_multiplier | Labor cost multiplier for overtime work | +| Allow same flag | allow_same_flag | flag to indicate whether choosing same base and topping crane is allowed (true/false) | +| Override total management cost for distributed (0 does not override) | override_total_management_cost_for_distributed | For distributed wind project, override the calculated management cost and use this value instead (0 means do not override) | +| Markup contingency | markup_contingency | Markup contingency | +| Markup warranty management | markup_warranty_management | Markup warranty management | +| Markup sales and use tax | markup_sales_and_use_tax | Markup sales and use tax | +| Markup overhead | markup_overhead | Markup overhead | +| Markup profit margin | markup_profit_margin | Markup profit margin | +| Utility Interconnection Fees (Small DW only) | utility_interconnection_fees_distributed_wind | Fee for connecting to the grid (distributed wind projects only) | +| Labor cost multiplier | labor_cost_multiplier | Multiplier to modify labor costs | +| Crane breakdown fraction | crane_breakdown_fraction | What fraction of cranes will breakdown. 0 means none, 1 means all. Breakdowns increase the total erection duration | +| No mapping available | enable_cost_and_scaling_modifications | Should cost and scaling modifications be applied (true/false) | + +### Project Excel Data + +Regardless of how the above data are provided, an Excel file will be required for individual project +configurations. These data will contain various cost, logistics, site, and engineering data. Each +of the following subsections will show up to the first 10 rows of the data in `ge15_public.xlsx` +to demonstrate the data and formats required for the input data. + +For each sheet below, except `weather_window`, additional columns can be provided after the listed, +required columns. These can be things such as notes and sources that are helpful for tracking +source data and any methodologies for transforming them to fit the LandBOSSE formats. In many +of the sheets in `ge15_public.xlsx`, there will be one or multiple notes and sources columns for +exactly this purpose. However, those data are not exemplified below. + +#### `components` + +The `components` sheet contains detailed information about any large scale, assembled on-site +component, such as tower sections, the nacelle, or blades. Each individual component should be +recorded in a single row (i.e. each blade gets 1 row even if they are exactly the same). + +Component +: Name of the component; can be specific or generic. For items where there are more than one of them + or they are are part of a whole like tower sections or blades, number them using 1-indexing, + e.g., "Tower 1", "Tower 2", "Tower 3". + +Mass tonne +: Mass in metric tonnes. + +Lift height m +: Height, in $m$, that a crane will have to lift the component in order to complete assembly. + +Surface area sq m +: Total surface area, in $m^2$, of a cross-section of the component. This will be used for + calculating thefoundational load. + +Coeff drag +: Coefficient of drag. This will be used to understand the effective mass while lifting the component. + +Coeff drag (installed) +: Coefficient of drag once the component is installed. This will be used for calculating the + foundational load. + +Section height m +: Total height ($m$) of a cross-section of the component. This will be used for calculating the + foundational load. + +Lever arm m +: Perpendicular distance, in $m$, from center of the foundation. + +Cycle time installation hrs +: Amount of time, in hours, required to prepare the component for assembly. + +Offload hook height m +: Height of the hook ($m$) above the top of the component to account for the total height of the crane's lift. + +Offload cycle time hrs +: Amount of time (in hours) required to detach the component from the crane. + +Multplier drag rotor +: Multiplier for accounting for the additional drag of the rotor for computing the foundation load. + This should only apply to the nacelle and blades + +Multiplier tower drag +: Multiplier for accounting for the additional drag of the tower for computing the foundation load. + +The following data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Component | Mass tonne | Lift height m | Surface area sq m | Coeff drag | Coeff drag (installed) | Section height m | Lever arm m | Cycle time installation hrs | Offload hook height m | Offload cycle time hrs | Multplier drag rotor | Multiplier tower drag | +|-------------------|--------------|-----------------|---------------------|--------------|--------------------------|--------------------|---------------|-------------------------------|-------------------------|--------------------------|------------------------|-------------------------| +| Nacelle GE 1.5SLE | 50 | 90 | 33 | 0.8 | 0.8 | 0 | 80 | 1.5 | 6 | 0.5 | 1 | 0 | +| Hub | 15.4 | 90 | 11.3 | 1.1 | 1.1 | 0 | 80 | 1 | 6 | 0.5 | 0 | 0 | +| Blade 1 | 5.2 | 90 | 33.44 | 0.1 | 1.4 | 0 | 80 | 1 | 6 | 0.5 | 0.666667 | 0 | +| Blade 2 | 5.2 | 90 | 33.44 | 0.1 | 1.4 | 0 | 80 | 1 | 6 | 0.5 | 0.666667 | 0 | +| Blade 3 | 5.2 | 90 | 33.44 | 0.1 | 1.4 | 0 | 80 | 1 | 6 | 0.5 | 0.666667 | 0 | +| Tower section 1 | 59.8 | 30 | 95.89 | 0.6 | 1.1 | 25 | 12 | 1 | 6 | 0.5 | 0 | 1 | +| Tower section 2 | 39.3 | 60 | 96.25 | 0.6 | 1.1 | 25 | 37 | 1 | 6 | 0.5 | 0 | 1 | +| Tower section 3 | 30.9 | 90 | 90 | 0.6 | 1.1 | 30 | 65 | 1 | 6 | 0.5 | 0 | 1 | + +#### `cable_specs` + +The `cable_specs` sheet should contain information about the array cables potentially used on site. +The specific types and quantities will be sized according to LandBOSSE's collection system. + +Array Cable +: Name or type of the array cable. + +Conductor Size (mm2) +: Cable cross section, in $mm^2$. + +Current Capacity (A) +: Cable current capacity at 1m burial depth, in $A$. + +Rated Voltage (V) +: Cable rated line-to-line voltage, in $V$. + +AC Resistance (Ohms/km) +: Cable resistance for the AC current per kilometer, in $\frac{\omega}{km}$ + +Inductance (mH/km) +: Cable inductance per kilometer, in $\frac{mH}{km}$ + +Capacitance (nF/km) +: Cable capacitance per kilometer, in $\frac{nF}{km}$ + +Cost (USD/LF) +: Cost of the cable per linear foot ($\frac{USD}{LF}$). + +The following data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Array Cable | Conductor Size (mm2) | Current Capacity (A) | Rated Voltage (V) | AC Resistance (Ohms/km) | Inductance (mH/km) | Capacitance (nF/km) | Cost (USD/LF) | +|---------------|------------------------|------------------------|---------------------|---------------------------|----------------------|-----------------------|-----------------| +| AWG 1/0 | 120 | 300 | 36 | 0.253 | 0.398 | 0.179 | 6 | +| AWG 4/0 | 240 | 440 | 36 | 0.125 | 0.359 | 0.223 | 9 | +| MCM 500 | 500 | 640 | 36 | 0.0605 | 0.317 | 0.293 | 13 | +| MCM1000 | 800 | 830 | 36 | 0.0367 | 0.291 | 0.375 | 16 | +| MCM1250 | 1000 | 935 | 36 | 0.0291 | 0.284 | 0.411 | 17 | + +#### `equip` + +The `equip` sheet is for information about the equipment grouping required for each general operational +category. The optimal equipment will be chosen based on a comparison of the equipment grouping's +capabilities and the components being lifted. + +Equipment ID +: Unique identififer for the equipment group. + +Operation +: One of "Top", "Base", or "Offload" to indicate what grouping of operations the equipment can + perform. + +Equipment name +: Name of the equipment in the equipment group. + +Crane capacity tonne +: Maximum capacityof the crane, in metric tonnes. + +Number of equipment +: Number of the equipment used during the operation. + +The following subset of the data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Equipment ID | Operation | Equipment name | Crane capacity tonne | Number of equipment | +|----------------|-------------|------------------|------------------------|-----------------------| +| E1 | Base | Crawler crane | 500 | 1 | +| E1 | Base | Truck crane | 50 | 1 | +| E1 | Top | Crawler crane | 500 | 1 | +| E1 | Top | Truck crane | 50 | 2 | +| E2 | Top | Crawler crane | 600 | 1 | +| E2 | Top | Truck crane | 50 | 2 | +| E2 | Top | RT | 100 | 2 | +| E3 | Top | Crawler crane | 750 | 1 | +| E3 | Top | RT | 100 | 2 | +| E4 | Top | Crawler crane | 1000 | 1 | +| ... | ... | ... | ... | ... | + +#### `crane_specs` + +The `crane_specs` sheet should contain all the detailed information about a crane's operating +limits and capacities. + +Equipment name +: Name matching with the `equip` sheet. + +Crane name +: Crane model name + +Boom system +: Type of boom system used on the crane. Primarily used for logging crane details. + +Crane capacity tonne +: Maximum crane capacity. Used for matching cranes to components for ideal assembly costs and speeds. + +Speed of travel km per hr +: Ground travel speed, in $km/h$ + +Hoist speed m per min +: Crane lifting rate, in $m/min$. + +Crew type ID +: Unique identifer for the type of crew required for the operation. + +Equipment ID +: Unique identifier matching with the `equip` sheet. + +Setup time hr +: Amount of time, in hours, required for the crane to be prepared at a new lift location. + +Breakdown time hr +: Amount of time, in hours, required for the crane to be broken down prior to being moved to a new + lift location. + +Max wind speed m per s +: Maximum allowable windspeed allowed during operations, in $m/s$. + +Hub height m +: Maximum lift height for the crane, in $m$. + +Max capacity tonne +: Maximum lift capacity for the crane, in metric tonnes. + +Radius m +: Undefined, and potentially unused. + +Hook Height m +: Height of the hook above the top of the component to be lifted. Used for the total lift mass and + wind speed calculations. + +Mobilization cost USD +: Cost to mobilize the crane for the duration of the installation period, in USD. + +The following subset of the data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Equipment name | Crane name | Boom system | Crane capacity tonne | Speed of travel km per hr | Hoist speed m per min | Crew type ID | Equipment ID | Setup time hr | Breakdown time hr | Max wind speed m per s | Hub height m | Max capacity tonne | Radius m | Hook Height m | Mobilization cost USD | +|------------------|--------------|------------------|------------------------|-----------------------------|-------------------------|----------------|----------------|-----------------|---------------------|--------------------------|----------------|----------------------|------------|-----------------|-------------------------| +| Offload crane | LB 75 | Hydraulic | 75 | 40 | 60 | C0 | OL1 | 0 | 0 | 10 | 12.5 | 38 | 5.4 | 12.5 | 8040 | +| Offload crane | Big LB 2580 | Big Hydraulic | 500 | 40 | 60 | C0 | OL2 | 0 | 0 | 10 | 48 | 500 | 11 | 48 | 406100 | +| Offload crane | LB 258 | Hydraulic | 200 | 40 | 60 | C0 | OL2 | 0 | 0 | 10 | 48 | 63 | 11 | 48 | 40610 | +| Crawler crane | M999 | 22EL | 275 | 2 | 20 | C1 | B1 | 0 | 40 | 9 | 57 | 67 | 14 | 57 | 68709 | +| Crawler crane | LR1500 | SL3F | 500 | 2 | 20 | C1 | E1 | 0 | 40 | 9 | 80 | 102 | 16 | 94 | 184398 | +| Crawler crane | LR1500 | SL3F | 500 | 2 | 20 | C1 | E1 | 0 | 40 | 9 | 85 | 95 | 16 | 100 | 184398 | +| Crawler crane | LR1500 | SL3F | 500 | 2 | 20 | C1 | E1 | 0 | 40 | 9 | 90 | 87 | 16 | 106 | 184398 | +| Crawler crane | LR1500 | SL3F | 500 | 2 | 20 | C1 | E1 | 0 | 40 | 9 | 100 | 77 | 18 | 112 | 184398 | +| Crawler crane | LR1500 | SL4DFB + Derrick | 500 | 2 | 20 | C1 | E1 | 2 | 40 | 9 | 80 | 112 | 16 | 94 | 184398 | +| Crawler crane | LR1500 | SL4DFB + Derrick | 500 | 2 | 20 | C1 | E1 | 2 | 40 | 9 | 90 | 105 | 16 | 100 | 184398 | +| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | + +#### `development` + +The `development` sheet contains any project development costs that are unaccounted for in the other +project specifications. + +Type of cost +: Development cost category. + +Cost USD +: Total cost, in USD. + +Phase of construction +: Phase of construction where the cost is incurred, likely alway "Development". + +The following data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Type of cost | Cost USD | Phase of construction | +|------------------|------------|-------------------------| +| Equipment rental | 0 | Development | +| Labor | 1000000 | Development | +| Materials | 0 | Development | +| Mobilization | 0 | Development | +| Other | 0 | Development | + +#### `crew_price` + +The `crew_price` sheet contains information about the hourly and daily costs of having a single crew +member on site for each labor category. + +Labor type ID +: Unique labor type identifier, matching with `crew`. + +Hourly rate USD per hour +: Hourly cost of the crew per hour, in $USD/hr$. + +Per diem USD per day +: Daily cost for food, etc. for the type of crew member, in $USD/day$. + +The following subset of the data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Labor type ID | Hourly rate USD per hour | Per diem USD per day | +|----------------------|----------------------------|------------------------| +| Crane operator | 81.9105 | 149 | +| Oiler | 61.625 | 149 | +| Rigger | 85.84 | 149 | +| Truck driver | 66.41 | 149 | +| Iron worker | 94.5545 | 149 | +| Project manager | 119 | 149 | +| Site manager | 112.2 | 149 | +| Construction manager | 112.2 | 149 | +| Project engineer | 93.5 | 149 | +| Safety or qc manager | 106.118 | 149 | +| ... | ... | ... | + +#### `crew` + +The `crew` sheet is for information about the amount and type of labor required in a crew category. + +Crew type ID +: Unique crew type identifier, matching with `crane_specs` + +Operation +: General operational category for the type of crew member. + +Crew name +: Name of the crew type. + +Labor type ID +: Unique labor type identifier for the type of crew member. + +Number of workers +: Number of workers in the labor type that make up one unit of the crew. + +The following subset of the data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Crew type ID | Operation | Crew name | Labor type ID | Number of workers | +|----------------|-----------------------|--------------------------------|----------------------|---------------------| +| M0 | Management | Management - project size | Project manager | 1 | +| M0 | Management | Management - project size | Site manager | 1 | +| M0 | Management | Management - project size | Construction manager | 1 | +| M0 | Management | Management - project size | Project engineer | 1 | +| M0 | Management | Management - project size | Safety or qc manager | 1 | +| M0 | Management | Management - project size | Logistics manager | 1 | +| M0 | Management | Management - project size | Office admin | 1 | +| M1 | Management | Management - rate construction | Tool room | 1 | +| M1 | Management | Management - rate construction | Electrician | 2 | +| MC0 | Mechanical completion | Mechanical completion | QC/QA tech | 2 | +| ... | ... | ... | ... | ... | + +#### `equip_price` + +The `equip_price` sheet is for information about the operational costs for a single crane. + +Equipment name +: Name of the equipment. + +Crane capacity tonne +: Maximum capacity of the crane, in metric tonnes. + +Equipment price USD per hour +: Hourly cost of the equipment, in $USD/hr$. + +Cost USD per breakdown +: Total cost to breakdown the equipment before moving to another lift site, in USD. + +Fuel consumption gal per day +: Expected daily fuel consumption, in $gal/day$. + +The following subset of the data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Equipment name | Crane capacity tonne | Equipment price USD per hour | Cost USD per breakdown | Fuel consumption gal per day | +|------------------|------------------------|--------------------------------|--------------------------|--------------------------------| +| Mobile crane | 75 | 35 | nan | 44 | +| Mobile crane | 200 | 149 | nan | 64 | +| Crawler crane | 275 | 217 | 37674 | 76 | +| Crawler crane | 250 | 194 | 30534 | 72 | +| Crawler crane | 400 | 330 | 73375 | 97 | +| Crawler crane | 500 | 420 | 101936 | 113 | +| Crawler crane | 600 | 511 | 130497 | 130 | +| Crawler crane | 750 | 647 | 173339 | 154 | +| Crawler crane | 1000 | 873 | 244741 | 195 | +| Crawler crane | 1350 | 1190 | 344705 | 252 | +| ... | ... | ... | ... | ... | + +#### `material_price` + +The `material_price` sheet is about the construction materials costs for aspects such as road and +foundation building, not turbine components. + +Material type ID +: Unique material identifier + +Material price USD per unit +: Cost of the materials per unit, in $USD/unit$. + +Unit +: Measurement units used for measuring the material's quantity. + +The following data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Material type ID | Material price USD per unit | Unit | +|------------------------------------|-------------------------------|-------------------------------| +| unique identifier for the material | price of material per unit | unit of measure used for cost | +| Concrete 3000 psi | 117 | cubic yard | +| Concrete 5000 psi | 140 | cubic yard | +| Concrete 8000 psi | 130 | cubic yard | +| Steel - rebar | 1120 | ton (short) | +| Road base - 3/4 inch crushed stone | 15 | Loose cubic yard | +| Excavated dirt | 0 | cubic yard | +| Backfill | 0 | cubic yard | + +#### `rsmeans` + +The `rsmeans` sheet for any relevant RSMeans operational cost data. + +Operation ID +: Unique identifier for the operation. + +Type of cost +: Cost category. + +Material type ID +: Type of material used, should match `material_price`. + +Rate USD per unit +: Cost per unit, in $USD/unit$ + +Units +: Measurment units. + +Daily output +: Daily output of the operation. + +Per Diem Hours (per unit) +: Additional hourly per diem costs per measured unit. + +Module +: Construction phase category. Should be one of "Foundations", "Roads", or "Collection". + +Number of workers +: Number of workers required for the operation type. + +The following subset of data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Operation ID | Type of cost | Material type ID | Rate USD per unit | Units | Daily output | Per Diem Hours (per unit) | Module | Number of workers | +|----------------------------------------------|------------------|------------------------------------|---------------------|------------------------------|----------------|-----------------------------|-------------|---------------------| +| Concrete placement | Equipment rental | Concrete 5000 psi | 4.61 | $/cubic yard | | | Foundations | | +| Rebar installation | Equipment rental | Steel - rebar | 0 | $/ton (short) | | | Foundations | | +| Survey | Equipment rental | | | | | | Roads | | +| Clear and grub | Equipment rental | | | | | | Roads | | +| Topsoil stripping and stockpiling | Equipment rental | | 1.63 | cubic yard | | 0 | Roads | 1 | +| Stormwater pollution prevention | Equipment rental | | | | | | Roads | | +| Culverts | Equipment rental | | | | | | Roads | | +| Compaction of soil (subgrade and crane path) | Equipment rental | | 1.15 | embankment cubic yards crane | | 0 | Roads | 3 | +| Mass material movement (cut and fill) | Equipment rental | | | | | | Roads | | +| Placing road base (hauling) | Equipment rental | Road base - 3/4 inch crushed stone | 5.16 | loose cubic yard | | 0 | Roads | 1 | +| ... | ... | ... | ... | ... | ... | ... | ... | ... | + +#### `site_facility_building_area` + +The `site_facility_building_area` is for sizing the wind farm's on-site facility appropriately for +the wind power plant's size. + +Size Min (MW) +: Minimum wind power plant size to estimate the site facility building size, in $MW$. + +Size Max (MW) +: Maximum wind power plant size to estimate the site facility building size, in $MW$. + +Building area (sq. ft.) +: Building size for site facilities, in ${ft}^2$. + +The following data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). + +| Size Min (MW) | Size Max (MW) | Building area (sq. ft.) | +|-----------------|-----------------|---------------------------| +| 0 | 200 | 3000 | +| 200 | 500 | 5000 | +| 500 | 800 | 7000 | +| 800 | 1000 | 9000 | +| 1000 | 5000 | 12000 | + +#### `weather_window` + +The hourly weather profiles uses 4 columns with 3 header rows formatted like the following table. +In the following data, taken from the GE 1.5 MW public example (`ge15_public.xlsx`), the first +row should contain the measurement units, and the second row should indicate the height at which +the measurement was taken, in $m$. + +| | Temperature | Pressure | Direction | Speed | +| ------------------- | ----------- | ---------- | --------- | ------ | +| | C | atm | Degrees | m/s | +| | 100 | 100 | 100 | 100 | +| 2012-01-01 12:00:00 | 2.444 | 0.95205318 | 185 | 8.681 | +| 2012-01-01 13:00:00 | 1.655 | 0.95227456 | 270 | 7.234 | +| 2012-01-01 14:00:00 | 2.512 | 0.9524854 | 322 | 12.898 | +| 2012-01-01 15:00:00 | 2.589 | 0.953325 | 321 | 14.795 | +| 2012-01-01 16:00:00 | 1.534 | 0.95440628 | 323 | 15.076 | +| 2012-01-01 17:00:00 | 1.014 | 0.95551016 | 322 | 15.53 | +| ... | ... | ... | ... | ... | + +## Running LandBOSSE + +The two primary means for running LandBOSSE are through the terminal using only Excel-based data, +or through Python (script, IDE, Jupyter Notebook, etc.). The following sections will walk through +running LandBOSSE through each of these methods. + +### Terminal + +Per the installation instructions, this example assumes your conda (or other) Python environment +has been created and LandBOSSE has been installed. + +1. Determine the desired input and output folder locations for your data. +2. Configure your project listing Excel file and the project data Excel file for each listed project + described in [Project Input Data](#project-input-data). + + :::{important} The name of the project listing must be called `project_list.xlsx` as it will + be the only file that is used for running projects. + ::: + +3. Open a terminal (or Anaconda Prompt or other) session. +4. Navigate to where LandBOSSE has been downloaded. In the terminal: + + ```bash + cd /path/to/LandBOSSE + ``` + +5. Activate your Python environment. For conda environments, but be sure to use the name of your + environment: + + ```bash + conda activate landbose + ``` + +6. Run all validLandBOSSE, where `-i` can be substituted for `--input`, and `-o` for `--output`. + + ```bash + python main.py -i /path/to/input-folder -o /path/to/output-folder + ``` + + Additional run flags also exist: + + - `-s` or `--scaling` for scaling study mode. This method modifies each row of the project list + after it has been modified by the parameters for to scale certain input values based on what + has been parametrically modified. + - `-v` or `--validate` which creates the file path for the output file from prior LandBOSSE run + that will be used to check latest run. The validation output file must be in the inputs folder + and must be called `landbosse-output-validation.xlsx`. + +### `LandBOSSERunner` + +#### Converting the Excel project list to a dictionary + +The below code snippet demonstrates how to convert the project list file for a given project, such +as the "foundation_validation_ge15" project found in `project_list_simplified.xlsx` that is +expemplified throughout this walkthrough. Please read the in-code comments for further context +about what steps are being taken and why. + +```python +import pandas as pd + +from landbosse.landbosse_runner import LandBOSSERunner + +inputs = LandBOSSERunner( + filename="/path/to/LandBOSSE/project_input_template/project_list_simplified.xlsx", + project_id="foundation_validation_ge15", + enable_cost_and_scaling_modifications=False, +) + +# Add a missing value from the Excel data that is used in the dictionary-based model +inputs["turbine_capex"] = 3500 + +# Load the data tables +# NOTE: the Excel input data as provided in this repository contains neither the path to +# the file, nor the extension, so they must be added here +inputs["data_tables"] = pd.read_excel( + f"/path/to/LandBOSSE/project_input_template/project_data/{inputs['data_tables']}.xlsx", + sheet_name=None, +) +``` + +#### Running the model + +1. Determine the desired input and output folder locations for your data. +2. Configure your project listing Excel file and the project data Excel file for each listed project + described in [Project Input Data](#project-input-data). +3. In a Python script, Jupyter Notebook, etc., some form of the following code can be used to run + a single project listing. Please read the inline comments for further context about what steps + are beging taken and why. + + ```python + from pathlib import Path + + import yaml + import pandas as pd + + from landbosse.landbosse_runner import LandBOSSERunner + + # If your data are stored in a YAML file (preferable), load them first, or + # create a data dictionary in place of the following code. + with Path("/path/to/my_project_data.yaml").open() as f: + inputs = yaml.safe_load(f) + + # Load the Excel project data. If the value of "data_tables" is relative to where the + # code will be run, simply exclude the `data_path` portion of the following code. + data_path = Path("/path/to/data_tables/").resolve() + inputs["data_tables"] = pd.read_excel( + data_path /inputs["data_tables"], sheet_name=None + ) + + # Optional: load alternative weather data + weather = pd.read_csv("/my/weather/data.csv") # replace csv with your file format + weather = LandBOSSERunner.add_header_to_weather_dataframe(weather) + + # Create your runner object, and run the analysis. Simply exclude the weather + # keyword argument if yours is contained in the `data_tables` + lb = LandBOSSERunner(input_config=inputs, weather=weather) + lb.run() + ``` + +4. Once the above code (or similar) is successfully run, the `result` object is created and attched + to the `LandBOSSERunner`. For complete details please see the `LandBOSSEResult` API documentation. + The `lb.result` (using the above examples naming convention for the runner object) contains the + following attributes as separate Pandas Series or DataFrames, and can be saved to CSV or one + Excel book as desired. + + - `project_parameters`: The values provided from the input dictionary. + - `data_sheets`: The Excel project data loaded as a dictionary of dataframes. + - `model_variables`: A copy of the model details that would traditionally be saved to Excel + when running LandBOSSE through the terminal. + - `operation_cost`: The detailed operational cost logs for the simulated installation. diff --git a/docs/examples.md b/docs/examples.md deleted file mode 100644 index b557eefc..00000000 --- a/docs/examples.md +++ /dev/null @@ -1,3 +0,0 @@ -# Examples - -Coming soon \ No newline at end of file diff --git a/landbosse/excelio/XlsxReader.py b/landbosse/excelio/XlsxReader.py index a8cf4b07..55022392 100644 --- a/landbosse/excelio/XlsxReader.py +++ b/landbosse/excelio/XlsxReader.py @@ -18,27 +18,16 @@ class XlsxReader: of data is read from the following sheets: - components - - cable_specs - - equip - - crane_specs - - development - - crew_price - - crew - - equip_price - - material_price - - rsmeans - - site_facility_building_area - - weather_window The second set of data are read from a single sheet as described below. diff --git a/landbosse/landbosse_runner.py b/landbosse/landbosse_runner.py index 47aee8a4..f17a7a05 100644 --- a/landbosse/landbosse_runner.py +++ b/landbosse/landbosse_runner.py @@ -3,6 +3,8 @@ """ import typing +from copy import deepcopy +from pathlib import Path import attrs import pandas as pd @@ -95,34 +97,13 @@ class LandBOSSERunner: "labor_cost_multiplier": "Multiplier to modify labor costs", "crane_breakdown_fraction": "What fraction of cranes will breakdown. 0 means none, 1 means " "all. Breakdowns increase the total erection duration", - "component": { - "nacelle": { - "mass_t": "nacelle mass (t)", - "surface_area_m2": "nacelle surface area (m^2)", - }, - "hub": { - "mass_t": "hub mass (t)", - "surface_area_m2": "hub surface area (m^2)", - }, - "blade": { - "mass_t": "Blade mass (t) (one blade)", - "surface_area_m2": "Blade surface area (m^2) (one blade)", - }, - "tower_section": { - "mass_t": "List of tower section masses (t), from bottom to top. Must be the same " - "length as the other tower section attributes", - "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 length as the other tower section attributes", - }, - }, + "user_trench_length_flag": "Flag (0 = no; 1 = yes) to indicate if the user-defined trench length should be used" } # Mapping from new parameter input names to those expected by LandBOSSE keys_rename: typing.ClassVar[dict] = { "id": "Project ID", - "datafile": "Project data file", + "data_tables": "Project data file", "construction_months": "Total project construction time (months)", "turbine_rating_MW": "Turbine rating MW", "hub_height_m": "Hub height m", @@ -172,11 +153,14 @@ class LandBOSSERunner: "DW only)", "labor_cost_multiplier": "Labor cost multiplier", "crane_breakdown_fraction": "Crane breakdown fraction", + "combined_homerun_trench_length_km": "Combined Homerun Trench Length to Substation (km)", + "user_trench_length_flag": "Flag for user-defined home run trench length (0 = no; 1 = yes)", } input_config: dict = attrs.field(converter=dict) weather: pd.DataFrame = attrs.field( - validator=attrs.validators.instance_of(pd.DataFrame), + default=None, + validator=attrs.validators.optional(attrs.validators.instance_of(pd.DataFrame)), ) result: LandBOSSEResult = attrs.field( validator=attrs.validators.instance_of(LandBOSSEResult), @@ -186,6 +170,38 @@ class LandBOSSERunner: def __attrs_post_init__(self): self.check_expected_configs_are_provided(self.input_config) + @staticmethod + def convert_excel_to_dict( + filename: str | Path, + project_id: str, + *, + enable_cost_and_scaling_modifications: bool = False, + ) -> dict: + """Convert a :py:attr:`project_id` from an Excel project list to a ``LandBOSSERunner`` + compliant dictionary. + + Parameters + ---------- + filename : str | Path + The project list file where the project's data can be found. + project_id : str + The ID for the project in the "Project ID" column of the project list. + enable_cost_and_scaling_modifications : bool, optional + Whether or not to enable the cost and scaling modifications, by default False. + + Returns + ------- + dict + The project listing data for a given :py:attr:`project_id` converted to a ``LandBOSSERunner``-compliant + format. + """ + df = pd.read_excel(filename) + data = df.loc[df["Project ID"].eq(project_id)].reset_index(drop=True).loc[0].to_dict() + keys_rename = {v: k for k, v in LandBOSSERunner.keys_rename.items()} + data = {keys_rename.get(k, k): v for k, v in data.items()} + data["enable_cost_and_scaling_modifications"] = enable_cost_and_scaling_modifications + return data + def check_expected_configs_are_provided(self, input_config: dict) -> None: """Checks to ensure all inputs required by the model have been provided. @@ -216,8 +232,12 @@ def get_project_parameters(self) -> pd.Series: ------- pd.Series Series containing input parameters for LandBOSSE with the required names + dict[str, pd.DataFrame] + Dictionary of the Excel project data with each sheet's name as a key and the + data loaded as a pandas DataFrame. """ - project_parameters_dict = self.input_config + project_parameters_dict = deepcopy(self.input_config) + data_sheets = project_parameters_dict.pop("data_tables") # Convert parameters dict to pandas Series (LandBOSSE expects a Series) project_parameters = pd.Series(project_parameters_dict, name="value") @@ -237,7 +257,7 @@ def get_project_parameters(self) -> pd.Series: project_parameters["Project ID with serial"] = project_parameters["Project ID"] - return project_parameters + return project_parameters, data_sheets def run(self) -> None: """Run the LandBOSSE model and save outputs in a LandBOSSEResult object instead of excel @@ -248,14 +268,11 @@ def run(self) -> None: LandBOSSEResult Outputs from LandBOSSE model """ - project_parameters = self.get_project_parameters() - data_sheets = project_parameters.pop("data_table") + project_parameters, data_sheets = self.get_project_parameters() - # Read WAVES weather data into expected LandBOSSE format - data_sheets["weather_window"] = self.add_header_to_weather_dataframe(self.weather) - - # Convert YAML component info into table format expected by LandBOSSE - data_sheets["components"] = self.create_component_dataframe(project_parameters, data_sheets) + # Prioritize weather profile provided at initialization over existing "weather_window" in Excel + if self.weather is not None: + data_sheets["weather_window"] = self.add_header_to_weather_dataframe(self.weather) xlsx_reader = XlsxReader() xlsx_reader.modify_project_data_and_project_list(data_sheets, project_parameters) @@ -338,99 +355,6 @@ def add_header_to_weather_dataframe(weather_window: pd.DataFrame) -> pd.DataFram ) return weather_window - @staticmethod - def create_component_dataframe( - project_parameters: pd.Series, - data_sheets: dict[str, pd.DataFrame], - ) -> pd.DataFrame: - """Convert the data from the input component data dictionary to the dataframe format - required by LandBOSSE. This includes rows for each separate blade and tower section. - - Parameters - ---------- - project_parameters : pd.Series - LandBOSSE YAML inputs - data_sheets : dict[str, pd.DataFrame] - LandBOSSE excel input tables - - Returns - ------- - pd.DataFrame - Component data in LandBOSSE format - """ - NUM_BLADES = 3 - - component_param = project_parameters["component"] - component_template = data_sheets["components"] - - component_nacelle = pd.Series(component_param["nacelle"], name="Nacelle") - component_nacelle["Component Name"] = "Nacelle" - - component_hub = pd.Series(component_param["hub"], name="Hub") - component_hub["Component Name"] = "Hub" - - component_blade = component_param["blade"] - component_blade["Component Name"] = "Blade" - - component_blade = pd.Series(component_blade) - component_blade = pd.concat( - objs={f"Blade {i+1:d}": component_blade for i in range(NUM_BLADES)}, - axis=1, - ) - - component_tower_section = pd.DataFrame(component_param["tower_section"]) - component_tower_section["Component Name"] = "Tower section" - component_tower_section = component_tower_section.set_axis( - [f"Tower section {i+1:d}" for i in range(len(component_tower_section.index))], - ) - component_tower_section["lift_height_m"] = ( - component_tower_section["height_m"].shift(-1).cumsum() - ) - component_tower_section["lever_arm_m"] = ( - component_tower_section["lift_height_m"] + component_tower_section["height_m"] / 2.0 - ) - - component_df = pd.concat( - objs=(component_nacelle, component_hub, component_blade, component_tower_section.T), - axis=1, - ).T - - hub_height = project_parameters["Hub height m"] - component_df = component_df.astype( - { - "height_m": float, - "lift_height_m": float, - "lever_arm_m": float, - } - ) - component_df = component_df.fillna( - { - "height_m": 0.0, - "lift_height_m": hub_height, - "lever_arm_m": hub_height, - } - ) - component_df = component_df.rename( - columns={ - "mass_t": "Mass tonne", - "surface_area_m2": "Surface area sq m", - "height_m": "Section height m", - "lift_height_m": "Lift height m", - "lever_arm_m": "Lever arm m", - } - ) - - component_combined = component_df.merge(component_template, on="Component Name") - component_combined = component_combined.drop(columns="Component Name") - component_combined.insert( - loc=0, - value=component_df.index, - column="Component", - ) - component_combined = component_combined.convert_dtypes() - - return component_combined - if __name__ == "__main__": pass diff --git a/landbosse/model/ErectionCost.py b/landbosse/model/ErectionCost.py index 74368478..03fe4f0f 100644 --- a/landbosse/model/ErectionCost.py +++ b/landbosse/model/ErectionCost.py @@ -144,7 +144,7 @@ def __init__(self, input_dict, output_dict, project_name): material_price (pd.DatFrame) Prices for various materials used during erection. rsmeans - (p.DataFrame) RSMeans data + (pd.DataFrame) RSMeans data output_dict : dict The output dictionary with key value pairs as found on the output documentation. diff --git a/landbosse/model/FoundationCost.py b/landbosse/model/FoundationCost.py index bab37e92..bddeeed6 100644 --- a/landbosse/model/FoundationCost.py +++ b/landbosse/model/FoundationCost.py @@ -158,7 +158,7 @@ def calculate_foundation_load(self, foundation_load_input_data, foundation_load_ * Section height m * Surface area sq m * Coeff drag (installed) - * Lever arm m m + * Lever arm m * Multplier drag rotor * Multiplier tower drag * Mass tonne diff --git a/pyproject.toml b/pyproject.toml index 780588af..ae057b7a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ dependencies = ['numpy', 'openpyxl', 'pandas', 'scipy', 'xlsxwriter'] [project.optional-dependencies] # Optional test = ["coveralls", "pytest"] docs = ["jupyter-book==1.*", "myst-parser", "sphinxcontrib-napoleon"] +develop = ["NREL-landbosse[test, docs]"] # List URLs that are relevant to your project # From 29deae5086ce131991c1723513444eafa645cf17 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Mon, 30 Mar 2026 15:28:55 -0700 Subject: [PATCH 4/6] Minor Docs Cleanup (#204) * add more details and step-by-step breakdown * remove quotes to remove confusion --- README.md | 2 +- docs/example.md | 66 ++++++++++++++++++++++++++++++++++++++++++------- docs/intro.md | 2 +- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9ba1c559..ec8348b3 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ pip install NREL-landbosse At its most basic, the following setup is required, though the provided input data in `project_inpute_template` can be used to test out the model and view results before diving into configuring custom scenarios. -1. Create an "input" and "output" folder for LandBOSSE to access. If you are using a source +1. Create an input and output folder for LandBOSSE to access. If you are using a source installation, then ensure the folders are not located inside the local copy of the repository. 2. Create a `project_list.xlsx` like `LandBOSSE/project_list.xlsx` and a subfolder called `project_data` inside of `inputs`. diff --git a/docs/example.md b/docs/example.md index e6c525ac..4bb9e38b 100644 --- a/docs/example.md +++ b/docs/example.md @@ -558,17 +558,20 @@ running LandBOSSE through each of these methods. Per the installation instructions, this example assumes your conda (or other) Python environment has been created and LandBOSSE has been installed. -1. Determine the desired input and output folder locations for your data. +1. Determine the desired input and output folder locations for your data, ensuring the input folder + contains project listing Excel sheets in the top-level of this folder, and all project-specific + Excel data in the `project_data` subfolder. This should mirror the + [repository's `project_input_template`](https://github.com/NLRWindSystems/LandBOSSE/tree/main/project_input_template). 2. Configure your project listing Excel file and the project data Excel file for each listed project described in [Project Input Data](#project-input-data). - + :::{important} The name of the project listing must be called `project_list.xlsx` as it will be the only file that is used for running projects. ::: 3. Open a terminal (or Anaconda Prompt or other) session. 4. Navigate to where LandBOSSE has been downloaded. In the terminal: - + ```bash cd /path/to/LandBOSSE ``` @@ -597,7 +600,7 @@ has been created and LandBOSSE has been installed. ### `LandBOSSERunner` -#### Converting the Excel project list to a dictionary +#### Converting The Excel Project List To A Dictionary The below code snippet demonstrates how to convert the project list file for a given project, such as the "foundation_validation_ge15" project found in `project_list_simplified.xlsx` that is @@ -627,14 +630,59 @@ inputs["data_tables"] = pd.read_excel( ) ``` -#### Running the model +#### Running In A Python Script -1. Determine the desired input and output folder locations for your data. +1. Determine the desired input and output folder locations for your data, ensuring the input folder + contains project listing Excel sheets in the top-level of this folder, and all project-specific + Excel data in the `project_data` subfolder. This should mirror the + [repository's `project_input_template`](https://github.com/NLRWindSystems/LandBOSSE/tree/main/project_input_template). 2. Configure your project listing Excel file and the project data Excel file for each listed project described in [Project Input Data](#project-input-data). -3. In a Python script, Jupyter Notebook, etc., some form of the following code can be used to run - a single project listing. Please read the inline comments for further context about what steps - are beging taken and why. +3. Manually load the project data and run the project (single workflow example after step-by-step + instructions). + + 1. Import the required dependencies. + + ```python + from pathlib import Path + + import yaml + import pandas as pd + + from landbosse.landbosse_runner import LandBOSSERunner + ``` + + 2. Optional: Load the hourly weather profile. + + ```python + weather = pd.read_csv("/my/weather/data.csv") + weather = LandBOSSERunner.add_header_to_weather_dataframe(weather) + ``` + + 3. Load the project listing Excel data. + + ```python + with Path("/path/to/my_project_data.yaml").open() as f: + inputs = yaml.safe_load(f) + ``` + + 4. Load the single project's Excel data and connect it to the project listing dictionary above. + + ```python + data_path = Path("/path/to/data_tables/").resolve() + inputs["data_tables"] = pd.read_excel( + data_path /inputs["data_tables"], sheet_name=None + ) + ``` + + 5. Create the LandBOSSE object and run + + ```python + lb = LandBOSSERunner(input_config=inputs, weather=weather) + lb.run() + ``` + + As a single, combined workflow, the below can serve as a base workflow for most projects. ```python from pathlib import Path diff --git a/docs/intro.md b/docs/intro.md index 2b26499f..e8aa3d2b 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -1,2 +1,2 @@ :::{include} ../README.md -::: \ No newline at end of file +::: From 337e15ea5c8a5d169e12901085e71885680f7ee9 Mon Sep 17 00:00:00 2001 From: Rob Hammond <13874373+RHammond2@users.noreply.github.com> Date: Thu, 7 May 2026 15:13:34 -0700 Subject: [PATCH 5/6] Documentation: TOC Ordering and Miscellaneous Updates (#205) * reorder documentation layout * update all github workflows for latests versions * update badge * fix typos * cleanup nrel references and add docs * NREL -> NLR * add missing dependency --- .github/workflows/ci.yml | 17 +++----- .github/workflows/gh_pages.yml | 2 +- .github/workflows/python-publish-test.yml | 6 +-- .github/workflows/python-publish.yml | 6 +-- README.md | 18 ++++----- docs/_config.yml | 19 --------- docs/_toc.yml | 4 +- docs/contributing.md | 2 +- docs/example.md | 22 +++++------ pyproject.toml | 47 ++++------------------- 10 files changed, 44 insertions(+), 99 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aca93726..87d8d502 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: CI_LandBOSSE +name: CI Tests # We run CI on push commits and pull requests on all branches on: [push, pull_request] @@ -9,12 +9,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Miniconda Python ${{ matrix.python-version }} - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: auto-update-conda: true python-version: ${{ matrix.python-version }} @@ -23,14 +23,9 @@ jobs: - name: Install Dependencies run: | python -m pip install --upgrade pip - python -m pip install pytest pandas numpy scipy xlsxwriter openpyxl openmdao + pip install -e .[develop] - - name: Pip Install LandBOSSE - run: | - pip install -e . -v - - # Run tests - - name: Pip Run pytest + - name: Run Tests run: | pytest landbosse/tests diff --git a/.github/workflows/gh_pages.yml b/.github/workflows/gh_pages.yml index 80b60674..6a6f89af 100644 --- a/.github/workflows/gh_pages.yml +++ b/.github/workflows/gh_pages.yml @@ -28,7 +28,7 @@ jobs: jupyter-book build docs - name: Upload artifact - uses: actions/upload-pages-artifact@v4 + uses: actions/upload-pages-artifact@v5 with: path: "docs/_build/html" diff --git a/.github/workflows/python-publish-test.yml b/.github/workflows/python-publish-test.yml index 7067618a..73ae8aea 100644 --- a/.github/workflows/python-publish-test.yml +++ b/.github/workflows/python-publish-test.yml @@ -20,12 +20,12 @@ jobs: id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version: '3.13' - name: Build package run: | diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 862358a4..a01595bd 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -19,12 +19,12 @@ jobs: id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version: '3.13' - name: Build package run: | diff --git a/README.md b/README.md index ec8348b3..11f834ad 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![PyPI version](https://badge.fury.io/py/NREL-landbosse.svg)](https://badge.fury.io/py/NREL-landbosse) [![Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![image](https://img.shields.io/pypi/pyversions/NREL-landbosse.svg)](https://pypi.python.org/pypi/NREL-landbosse) -[![Jupyter Book](https://jupyterbook.org/badge.svg)](https://nlrwindsystems.github.io/LandBOSSE) +[![Jupyter Book Badge](https://raw.githubusercontent.com/jupyter-book/jupyter-book/next/docs/media/images/badge.svg)](nlrwindsystems.github.io/LandBOSSE) ## Welcome to LandBOSSE! @@ -14,15 +14,15 @@ The methods used to develop this model (specifically, LandBOSSE Version 2.1.0) a Eberle, Annika, Owen Roberts, Alicia Key, Parangat Bhaskar, and Katherine Dykes. 2019. NREL’s Balance-of-System Cost Model for Land-Based Wind. Golden, CO: National Renewable Energy Laboratory. NREL/TP-6A20-72201. -https://www.nrel.gov/docs/fy19osti/72201.pdf. +https://www.nlr.gov/docs/fy19osti/72201.pdf. ## Part of the WETO Stack -LandBOSSE is primarily developed with the support of the U.S. Department of Energy and is part of the [WETO Software Stack](https://nrel.github.io/WETOStack). For more information and other integrated modeling software, see: -- [Portfolio Overview](https://nrel.github.io/WETOStack/portfolio_analysis/overview.html) -- [Entry Guide](https://nrel.github.io/WETOStack/_static/entry_guide/index.html) -- [Techno-Economic Modeling Workshop](https://nrel.github.io/WETOStack/workshops/user_workshops_2024.html#tea-and-cost-modeling) -- [Systems Engineering Workshop](https://nrel.github.io/WETOStack/workshops/user_workshops_2024.html#systems-engineering) +LandBOSSE is primarily developed with the support of the U.S. Department of Energy and is part of the [WETO Software Stack](https://natlabrockies.github.io/WETOStack). For more information and other integrated modeling software, see: +- [Portfolio Overview](https://natlabrockies.github.io/WETOStack/portfolio_analysis/overview.html) +- [Entry Guide](https://natlabrockies.github.io/WETOStack/_static/entry_guide/index.html) +- [Techno-Economic Modeling Workshop](https://natlabrockies.github.io/WETOStack/workshops/user_workshops_2024.html#tea-and-cost-modeling) +- [Systems Engineering Workshop](https://natlabrockies.github.io/WETOStack/workshops/user_workshops_2024.html#systems-engineering) ## User Guide @@ -30,7 +30,7 @@ LandBOSSE is primarily developed with the support of the U.S. Department of Ener For any installation, users should use a virtual environment. We recommend Miniconda or Anaconda, but any supporting PyPI or source installations are possible. Here, we'll work with conda for -compatibility with other NREL tools. +compatibility with other NLR tools. In the below, you can replace the name "landbosse" with any name you choose, and the Python version can be any that you prefer as long as it's supported by LandBOSSE. @@ -65,7 +65,7 @@ pip install NREL-landbosse ### First time running the model -At its most basic, the following setup is required, though the provided input data in `project_inpute_template` +At its most basic, the following setup is required, though the provided input data in `project_input_template` can be used to test out the model and view results before diving into configuring custom scenarios. 1. Create an input and output folder for LandBOSSE to access. If you are using a source diff --git a/docs/_config.yml b/docs/_config.yml index 0630f8cd..a80cb014 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -56,25 +56,6 @@ sphinx: show_toc_level: 2 repository_url: "https://github.com/NLRWindSystems/LandBOSSE" repository_branch: main - # icon_links: [ - # { - # name: GitHub, - # url: "https://github.com/NREL/WAVES", - # icon: fa-brands fa-github, - # }, - # { - # name: PyPI version, - # url: "https://pypi.org/project/WAVES/", - # icon: "https://img.shields.io/pypi/v/WAVES?link=https%3A%2F%2Fpypi.org%2Fproject%2FWAVES%2F", - # type: url, - # }, - # { - # name: Binder, - # url: "https://mybinder.org/v2/gh/NREL/WAVES/main?filepath=examples", - # icon: "https://mybinder.org/badge_logo.svg", - # type: url, - # }, - # ] language: 'python' autosummary_generate: true autodoc_default_options: diff --git a/docs/_toc.yml b/docs/_toc.yml index c2942f7e..95a9f2e1 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -4,6 +4,6 @@ format: jb-book root: intro chapters: -- file: api - file: example -- file: contributing \ No newline at end of file +- file: contributing +- file: api \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md index 1d8f2ed4..a051e5d4 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -21,7 +21,7 @@ ## Testing the Code Run LandBOSSE's testing suite using the following command. Please note the tests are not -particularly robust at this time, so passing tests after modifying the codeshould be viewed with +particularly robust at this time, so passing tests after modifying the code should be viewed with caution. ```bash diff --git a/docs/example.md b/docs/example.md index 4bb9e38b..eb85fe2e 100644 --- a/docs/example.md +++ b/docs/example.md @@ -113,7 +113,7 @@ Lift height m Surface area sq m : Total surface area, in $m^2$, of a cross-section of the component. This will be used for - calculating thefoundational load. + calculating the foundational load. Coeff drag : Coefficient of drag. This will be used to understand the effective mass while lifting the component. @@ -138,7 +138,7 @@ Offload hook height m Offload cycle time hrs : Amount of time (in hours) required to detach the component from the crane. -Multplier drag rotor +Multiplier drag rotor : Multiplier for accounting for the additional drag of the rotor for computing the foundation load. This should only apply to the nacelle and blades @@ -147,7 +147,7 @@ Multiplier tower drag The following data are used for the GE 1.5 MW public example (`ge15_public.xlsx`). -| Component | Mass tonne | Lift height m | Surface area sq m | Coeff drag | Coeff drag (installed) | Section height m | Lever arm m | Cycle time installation hrs | Offload hook height m | Offload cycle time hrs | Multplier drag rotor | Multiplier tower drag | +| Component | Mass tonne | Lift height m | Surface area sq m | Coeff drag | Coeff drag (installed) | Section height m | Lever arm m | Cycle time installation hrs | Offload hook height m | Offload cycle time hrs | Multiplier drag rotor | Multiplier tower drag | |-------------------|--------------|-----------------|---------------------|--------------|--------------------------|--------------------|---------------|-------------------------------|-------------------------|--------------------------|------------------------|-------------------------| | Nacelle GE 1.5SLE | 50 | 90 | 33 | 0.8 | 0.8 | 0 | 80 | 1.5 | 6 | 0.5 | 1 | 0 | | Hub | 15.4 | 90 | 11.3 | 1.1 | 1.1 | 0 | 80 | 1 | 6 | 0.5 | 0 | 0 | @@ -204,7 +204,7 @@ category. The optimal equipment will be chosen based on a comparison of the equi capabilities and the components being lifted. Equipment ID -: Unique identififer for the equipment group. +: Unique identifier for the equipment group. Operation : One of "Top", "Base", or "Offload" to indicate what grouping of operations the equipment can @@ -214,7 +214,7 @@ Equipment name : Name of the equipment in the equipment group. Crane capacity tonne -: Maximum capacityof the crane, in metric tonnes. +: Maximum capacity of the crane, in metric tonnes. Number of equipment : Number of the equipment used during the operation. @@ -259,7 +259,7 @@ Hoist speed m per min : Crane lifting rate, in $m/min$. Crew type ID -: Unique identifer for the type of crew required for the operation. +: Unique identifier for the type of crew required for the operation. Equipment ID : Unique identifier matching with the `equip` sheet. @@ -272,7 +272,7 @@ Breakdown time hr lift location. Max wind speed m per s -: Maximum allowable windspeed allowed during operations, in $m/s$. +: Maximum allowable wind speed allowed during operations, in $m/s$. Hub height m : Maximum lift height for the crane, in $m$. @@ -474,7 +474,7 @@ Rate USD per unit : Cost per unit, in $USD/unit$ Units -: Measurment units. +: Measurement units. Daily output : Daily output of the operation. @@ -580,7 +580,7 @@ has been created and LandBOSSE has been installed. environment: ```bash - conda activate landbose + conda activate landbosse ``` 6. Run all validLandBOSSE, where `-i` can be substituted for `--input`, and `-o` for `--output`. @@ -604,7 +604,7 @@ has been created and LandBOSSE has been installed. The below code snippet demonstrates how to convert the project list file for a given project, such as the "foundation_validation_ge15" project found in `project_list_simplified.xlsx` that is -expemplified throughout this walkthrough. Please read the in-code comments for further context +exemplified throughout this walkthrough. Please read the in-code comments for further context about what steps are being taken and why. ```python @@ -714,7 +714,7 @@ inputs["data_tables"] = pd.read_excel( lb.run() ``` -4. Once the above code (or similar) is successfully run, the `result` object is created and attched +4. Once the above code (or similar) is successfully run, the `result` object is created and attached to the `LandBOSSERunner`. For complete details please see the `LandBOSSEResult` API documentation. The `lb.result` (using the above examples naming convention for the runner object) contains the following attributes as separate Pandas Series or DataFrames, and can be saved to CSV or one diff --git a/pyproject.toml b/pyproject.toml index ae057b7a..64a86df3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,27 +11,16 @@ requires-python = ">=3.10" license = { text = "Apache-2.0" } keywords = ["wind", "turbine", "mdao", "design", "optimization"] authors = [ - { name = "NREL WISDEM Team", email = "systems.engineering@nrel.gov" }, + { name = "NLR WISDEM Team", email = "systems.engineering@nlr.gov" }, ] maintainers = [ - { name = "NREL WISDEM Team", email = "systems.engineering@nrel.gov" }, + { name = "NLR WISDEM Team", email = "systems.engineering@nlr.gov" }, ] -classifiers = [ # Optional - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable +classifiers = [ "Development Status :: 4 - Beta", - - # Indicate who your project is intended for "Intended Audience :: Science/Research", "Topic :: Scientific/Engineering", - "License :: OSI Approved :: Apache Software License", - - # Specify the Python versions you support here. In particular, ensure - # that you indicate you support Python 3. These classifiers are *not* - # checked by "pip install". See instead "python_requires" below. "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -43,41 +32,21 @@ classifiers = [ # Optional "Programming Language :: Fortran", ] -dependencies = ['numpy', 'openpyxl', 'pandas', 'scipy', 'xlsxwriter'] +dependencies = ['numpy', 'openpyxl', 'pandas', 'scipy', 'xlsxwriter', 'openmdao'] -# List additional groups of dependencies here (e.g. development -# dependencies). Users will be able to install these using the "extras" -# syntax, for example: -# -# $ pip install sampleproject[dev] -# -# Similar to `dependencies` above, these must be valid existing -# projects. [project.optional-dependencies] # Optional test = ["coveralls", "pytest"] docs = ["jupyter-book==1.*", "myst-parser", "sphinxcontrib-napoleon"] develop = ["NREL-landbosse[test, docs]"] -# List URLs that are relevant to your project -# -# This field corresponds to the "Project-URL" and "Home-Page" metadata fields: -# https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use -# https://packaging.python.org/specifications/core-metadata/#home-page-optional -# -# Examples listed include a pattern for specifying where the package tracks -# issues, where the source is hosted, where to say thanks to the package -# maintainers, and where to support the project financially. The key is -# what's used to render the link text on PyPI. -[project.urls] # Optional -"Homepage" = "https://github.com/WISDEM/LandBOSSE" -#"Documentation" = "https://wisdem.readthedocs.io" -"Project" = "https://www.nrel.gov/wind/systems-engineering.html" +[project.urls] +"Homepage" = "https://github.com/NLRWIndSystems/LandBOSSE" +"Documentation" = "https://nlrwindsystems.readthedocs.io" +"Project" = "https://www.nlr.gov/wind/systems-engineering.html" #[project.scripts] # What to do about main.py program -# This is configuration specific to the `setuptools` build backend. -# If you are using a different build backend, you will need to change this. [tool.setuptools] include-package-data = true From 4fc0ceeaa068833df7364e0f38730aa3d7b6efad Mon Sep 17 00:00:00 2001 From: "Hammond, Rob" <13874373+RHammond2@users.noreply.github.com> Date: Thu, 7 May 2026 15:15:14 -0700 Subject: [PATCH 6/6] bump version for release --- CHANGELOG.md | 2 +- landbosse/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4820278b..ecda8bfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # LandBOSSE Changelog -## Unreleased +## 2.6.3 (May 7, 2026) + Corrects an error in multiple names defined for `LandBOSSERunner`s data connection to project Excel file, which is now called "data_tables", consistent with the implementation made in diff --git a/landbosse/__init__.py b/landbosse/__init__.py index 45acc53b..dfb23b36 100644 --- a/landbosse/__init__.py +++ b/landbosse/__init__.py @@ -1,2 +1,2 @@ -__version__ = "2.6.2" +__version__ = "2.6.3"