diff --git a/.github/workflows/gh_pages.yml b/.github/workflows/gh_pages.yml new file mode 100644 index 00000000..80b60674 --- /dev/null +++ b/.github/workflows/gh_pages.yml @@ -0,0 +1,37 @@ +name: Documentation + +on: + push: + branches: [main] + +jobs: + make-pages: + runs-on: ubuntu-latest + permissions: + pages: write + id-token: write + steps: + - uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: 3.13 + + - name: Install dependencies + run: | + pip install --upgrade pip + pip install ".[docs]" + + - name: Build the documentation + run: | + jupyter-book build docs + + - name: Upload artifact + uses: actions/upload-pages-artifact@v4 + with: + path: "docs/_build/html" + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.gitignore b/.gitignore index 08ad2273..859441d2 100644 --- a/.gitignore +++ b/.gitignore @@ -149,3 +149,7 @@ landbosse/tests/*.csv # repository directoy, ignore them. outputs/ inputs/ + +# Docs build +_autosummary +_build \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f8cb99e..6d12f1d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,81 +1,84 @@ # LandBOSSE Changelog -## 2.0.0 (August 1, 2019) +## 2.6.2 (February 26, 2026) -- Refactored into an object-oriented programming (OOP) architecture. -- Enable parallel computation of separate projects. -- Created an interface that takes inputs and outputs from and to `.xlsx` spreadsheets. -- Enhancements to all modules in model. -- Black box tests. -- Dictionary based interface to integrate with other modeling codes. ++ Docstrings are reformatted to display nicely on a Jupyter Book documentation site. ++ Creates a docs site at ++ Removes the old documentation site and configuration for a more modern Jupyter Book + style site published to GitHub Pages for anyone to read. ++ Overhauls the README to bring it up to date with the current installation instructions. -## 2.1.1 (October 9, 2019) +## 2.6.1 (September 30, 2025) -- In the `costs_by_module_type_operation` tab, standardize all costs to USD/kW per project, cost per project, cost per turbine. -- Improve docstrings in source code. -- Refactor more functionality into a new `CostModule` class. -- Clean up logging to use simple `print()` statements which are safe to use in multi-process parallel logging operations. ++ Updates the PyPI listing -## 2.1.2 (October 24, 2019) +## 2.6.0 (February 12 2025) -- Add separated "numeric value" and "non-numeric value" to columns on the details sheet. -- Add support to test current model output against previously known good model output to guard against regressions when the model is changed. -- Add support for command line options to control validation, input folder and output folder so that environment variables are not needed. -- Added documentation about command line operation with flowcharts about how LandBOSSE processes data according to the command line. ++ Add basic API to integrate LandBOSSE into WAVES ++ Tidy up of code to remove warnings ++ Update to continuous integration script -## 2.1.3 (October 29, 2019) +## 2.2.7 -- Removed an empty and unimplemented function from `DefaultMasterInputDict.py`. ++ Changed construction duration functionality. ++ Weather window can now be extended to an arbitrarily long length by duplicating the underlying wind data. ++ All modules now report the actual construction time they require to perform the scope of work they model. ++ ManagementCost now keeps the management crew onsite for only the time necessary to complete all scope of work. -## 2.1.4 (November 1, 2019) +## 2.2.6 -- Enhanced `.xlsx` input performance for faster execution time. ++ Fix setup.py to automatically find the `landbosse` package. -## 2.1.5 (November 8, 2019) +## 2.2.5 -- Added outputs for erection crew cost, wind multiplier and mobilization of each process of the erection to the details output sheet. ++ Fixed a solver problem that would hang during foundation calculations. This was a bug encountered in the upgrade to SymPy 1.5.1 ++ Added post processing scripts to load data into PostgreSQL -## 2.2.0 (November 24, 2019) +## 2.2.2 (December 13, 2019) -- Support for parametric variable grid search added. ++ Added support for crane breakdowns ++ Fixed a roads issue. ## 2.2.1 (December 12, 2019) + Support for discrete value lists for parameteric variables added. - + Support for labor rate multipliers added. -## 2.2.2 (December 13, 2019) - -+ Added support for crane breakdowns - -+ Fixed a roads issue. - -## 2.2.5 - -+ Fixed a solver problem that would hang during foundation calculations. This was a bug encountered in the upgrade to SymPy 1.5.1 +## 2.2.0 (November 24, 2019) -+ Added post processing scripts to load data into PostgreSQL ++ Support for parametric variable grid search added. -## 2.2.6 +## 2.1.5 (November 8, 2019) -+ Fix setup.py to automatically find the `landbosse` package. ++ Added outputs for erection crew cost, wind multiplier and mobilization of each process of the erection to the details output sheet. -## 2.2.7 +## 2.1.4 (November 1, 2019) -+ Changed construction duration functionality. ++ Enhanced `.xlsx` input performance for faster execution time. -+ Weather window can now be extended to an arbitrarily long length by duplicating the underlying wind data. +## 2.1.3 (October 29, 2019) -+ All modules now report the actual construction time they require to perform the scope of work they model. ++ Removed an empty and unimplemented function from `DefaultMasterInputDict.py`. -+ ManagementCost now keeps the management crew onsite for only the time necessary to complete all scope of work. +## 2.1.2 (October 24, 2019) ++ Add separated "numeric value" and "non-numeric value" to columns on the details sheet. ++ Add support to test current model output against previously known good model output to guard against regressions when the model is changed. ++ Add support for command line options to control validation, input folder and output folder so that environment variables are not needed. ++ Added documentation about command line operation with flowcharts about how LandBOSSE processes data according to the command line. -## 2.6.0 (February 12 2025) +## 2.1.1 (October 9, 2019) -+ Add basic API to integrate LandBOSSE into WAVES ++ In the `costs_by_module_type_operation` tab, standardize all costs to USD/kW per project, cost per project, cost per turbine. ++ Improve docstrings in source code. ++ Refactor more functionality into a new `CostModule` class. ++ Clean up logging to use simple `print()` statements which are safe to use in multi-process parallel logging operations. -+ Tidy up of code to remove warnings +## 2.0.0 (August 1, 2019) -+ Update to continuous integration script ++ Refactored into an object-oriented programming (OOP) architecture. ++ Enable parallel computation of separate projects. ++ Created an interface that takes inputs and outputs from and to `.xlsx` spreadsheets. ++ Enhancements to all modules in model. ++ Black box tests. ++ Dictionary based interface to integrate with other modeling codes. diff --git a/README.md b/README.md index 68242cd0..a0eb0e4c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # LandBOSSE +[![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/NREL-landbosse) + ## Welcome to LandBOSSE! The Land-based Balance-of-System Systems Engineering (LandBOSSE) model is a systems engineering tool that estimates the balance-of-system (BOS) costs associated with installing utility scale wind plants (10, 1.5 MW turbines or larger). It can execute on macOS and Windows. At this time, for both platforms, it is a command line tool that needs to be accessed from the command line. @@ -11,34 +16,82 @@ 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. +## 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 +compatibility with other NREL 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. + +```bash +conda create -n landbosse python=3.13 -y +``` + +### PyPI + +```bash +pip install NREL-landbosse +``` + +### Source + +1. Navigate to your preferred installation location +2. Clone the repo (or fork and clone your fork, if preferred). + + ```bash + git clone https://github.com/NLRWindSystems/LandBOSSE.git + ``` + +3. Enter the directory and install the local version + + ```bash + cd LandBOSSE + pip install . + ``` + + Optional: `pip install -e .` for editable installations if you plan to modify the code itself. + ## 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. +### First time running teh 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. -In brief, LandBOSSE takes `.xlsx` spreadsheets, reads input data from tabs on the spreadsheets, and writes the results to an output `.xlsx` file. There are three sections in the user guide to demonstrate how to perform these steps. +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`. +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`. -The user guide comes in three parts: -1. Software installation, +### Running the model -2. Input data configuration, and +Once the initial steps (above) are followed, we can run the model: -3. Output data analysis. +1. Activate your virtual environment: `conda activate landbosse +2. Navigate to the top-level `LandBOSSE` folder +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). -### Software Installation +All together ```bash -pip install NREL-landbosse +conda activate landbosse +cd /path/to/LandBOSSE +python main.py -i /path/to/inputs -o /path/to/outputs +conda deactivate ``` -There are two options depending on whether you are a developer or an end user and what operating system you are running. - -- **Windows end-user**: If you run the Microsoft Windows operating system and aren't setting up as a developer who is going to be modifying the core library, these instructions are for you. [Find out how to configure Windows for end users.](installation_instructions/windows_end_user.md) +4. View your results in the output folder. -- **macOS end user** and **macOS developer**: If you run the macOS operating system, either as an end-user or as a developer, these instructions are for you. Both developers and end-users will need most of the steps. [Find out how to configure macOS for end users and developers.](installation_instructions/macos_developer.md) -### Operation after the installation +### Integrating LandBOSSE into your code -Review the installation instructions on how to activate a virtual environment, if you haven't already. +While LandBOSSE was originally designed as a CLI tool powered by Excel workbooks, an API also exists +to run the model within another application. -Then, read the [Operation and Folder Structure](installation_instructions/operation_and_folder_structure.md) for details on running the command that executes LandBOSSE from the command line. +Further documentation coming soon diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 298ea9e2..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 00000000..fe2d496f --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,86 @@ +# Book settings +# Learn more at https://jupyterbook.org/customize/config.html + +title: LandBOSSE +author: National Laboratory of the Rockies +# logo: logo.png + +# Force re-execution of notebooks on each build. +# See https://jupyterbook.org/content/execute.html +execute: + execute_notebooks: force + +# Define the name of the latex output file for PDF builds +latex: + latex_documents: + targetname: book.tex + +# Add a bibtex file so that we can create citations +bibtex_bibfiles: + - references.bib + +# Information about where the book exists on the web +repository: + url: https://github.com/NLRWindSystems/LandBOSSE + path_to_book: docs + branch: main + +# Add GitHub buttons to your book +# See https://jupyterbook.org/customize/config.html#add-a-link-to-your-repository +html: + use_issues_button: true + use_repository_button: true + +sphinx: + extra_extensions: + - "sphinx.ext.autodoc" + - "sphinx.ext.autosummary" + - "sphinx.ext.napoleon" + + config: + html_theme: sphinx_book_theme + html_theme_options: + use_issues_button: true + use_repository_button: true + use_edit_page_button: true + 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: + members: true + member-order: bysource + undoc-members: true + private-members: true + # special-members: true + # inherited-members + # show-inheritance + # ignore-module-all + # imported-members: true + # exclude-members + # class-doc-from + # no-value + autodoc_typehints: description + napoleon_use_admonition_for_notes: true + napoleon_use_rtype: false + nb_merge_streams: true diff --git a/docs/_toc.yml b/docs/_toc.yml new file mode 100644 index 00000000..2004a87b --- /dev/null +++ b/docs/_toc.yml @@ -0,0 +1,9 @@ +# Table of contents +# Learn more at https://jupyterbook.org/customize/toc.html + +format: jb-book +root: intro +chapters: +- file: api +- file: examples +- file: contributing \ No newline at end of file diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 00000000..58a0827f --- /dev/null +++ b/docs/api.md @@ -0,0 +1,49 @@ +# API Documentation + +## Model + +```{eval-rst} +.. currentmodule:: landbosse.model + +.. autosummary:: + :toctree: _autosummary + :recursive: + + CollectionCost + CostModule + DefaultMasterInputDict + DevelopmentCost + ErectionCost + FoundationCost + GridConnectionCost + ManagementCost + Manager + SitePreparationCost + SubstationCost + TransportCost + TurbineCost + WeatherDelay +``` + +## Excel I/O + +```{eval-rst} +.. currentmodule:: landbosse.excelio + +.. autosummary:: + :toctree: _autosummary + :recursive: + + CsvGenerator + GridSearchTree + WeatherWindowCSVReader + XlsxDataframeCache + XlsxFileOperations + XlsxGenerator + XlsxManagerRunner + XlsxOperationException + XlsxParallelManagerRunner + XlsxReader + XlsxSerialManagerRunner + XlsxValidator +``` diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 05ea1255..00000000 --- a/docs/conf.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('..')) - - -# -- Project information ----------------------------------------------------- - -project = 'MiniLandBOSSE' -copyright = '2019, NREL' -author = 'NREL' - -# The short X.Y version -version = '' -# The full version, including alpha/beta/rc tags -release = '' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.ifconfig', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', - 'sphinx.ext.napoleon' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = None - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'MiniLandBOSSEdoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'MiniLandBOSSE.tex', 'MiniLandBOSSE Documentation', - 'NREL', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'landbosse', 'MiniLandBOSSE Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'MiniLandBOSSE', 'MiniLandBOSSE Documentation', - author, 'MiniLandBOSSE', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Options for Epub output ------------------------------------------------- - -# Bibliographic Dublin Core info. -epub_title = project - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -# -# epub_identifier = '' - -# A unique identification for the text. -# -# epub_uid = '' - -# A list of files that should not be packed into the epub file. -epub_exclude_files = ['search.html'] - - -# -- Extension configuration ------------------------------------------------- - -# -- Options for todo extension ---------------------------------------------- - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True - -# From https://stackoverflow.com/questions/5599254/how-to-use-sphinxs-autodoc-to-document-a-classs-init-self-method - - -def skip(app, what, name, obj, would_skip, options): - if name == '__init__': - return False - return would_skip - - -def setup(app): - app.connect('autodoc-skip-member', skip) - - -# -- Read the docs Sphinx theme ------------------------------------------------- -html_theme = 'sphinx_rtd_theme' -html_theme_options = { - 'canonical_url': '', - # 'analytics_id': 'UA-XXXXXXX-1', # Google Analytics id not yet used by the theme, but is here as a placeholder - 'logo_only': False, - 'display_version': True, - 'prev_next_buttons_location': 'bottom', - 'style_external_links': False, - 'vcs_pageview_mode': '', - 'style_nav_header_background': 'white', - # Toc options - 'collapse_navigation': True, - 'sticky_navigation': True, - 'navigation_depth': 4, - 'includehidden': True, - 'titles_only': False -} - -mathjax_path = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 00000000..3302eb19 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,3 @@ +# Contributor's Guide + +Coming soon. \ No newline at end of file diff --git a/docs/doc_CollectionCost.rst b/docs/doc_CollectionCost.rst deleted file mode 100644 index 55b6a676..00000000 --- a/docs/doc_CollectionCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -CollectionCost -============== - -.. automodule:: landbosse.model.CollectionCost - :members: diff --git a/docs/doc_CostModule.rst b/docs/doc_CostModule.rst deleted file mode 100644 index da395ca5..00000000 --- a/docs/doc_CostModule.rst +++ /dev/null @@ -1,5 +0,0 @@ -CostModule -========== - -.. autoclass:: landbosse.model.CostModule - :members: \ No newline at end of file diff --git a/docs/doc_DefaultMasterInputDict.rst b/docs/doc_DefaultMasterInputDict.rst deleted file mode 100644 index 2d822da5..00000000 --- a/docs/doc_DefaultMasterInputDict.rst +++ /dev/null @@ -1,5 +0,0 @@ -DefaultMasterInputDict -====================== - -.. autoclass:: landbosse.model.DefaultMasterInputDict - :members: diff --git a/docs/doc_ErectionCost.rst b/docs/doc_ErectionCost.rst deleted file mode 100644 index 28b77cb4..00000000 --- a/docs/doc_ErectionCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -ErectionCost -============ - -.. autoclass:: landbosse.model.ErectionCost - :members: \ No newline at end of file diff --git a/docs/doc_FoundationCost.rst b/docs/doc_FoundationCost.rst deleted file mode 100644 index db7bfe58..00000000 --- a/docs/doc_FoundationCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -FoundationCost -============== - -.. autoclass:: landbosse.model.FoundationCost - :members: diff --git a/docs/doc_GridConnectionCost.rst b/docs/doc_GridConnectionCost.rst deleted file mode 100644 index 3e602a2a..00000000 --- a/docs/doc_GridConnectionCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -GridConnectionCost -================== - -.. autoclass:: landbosse.model.GridConnectionCost - :members: \ No newline at end of file diff --git a/docs/doc_ManagementCost.rst b/docs/doc_ManagementCost.rst deleted file mode 100644 index d046edc9..00000000 --- a/docs/doc_ManagementCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -ManagementCost -================ - -.. autoclass:: landbosse.model.ManagementCost - :members: \ No newline at end of file diff --git a/docs/doc_Manager.rst b/docs/doc_Manager.rst deleted file mode 100644 index 7e72fa7a..00000000 --- a/docs/doc_Manager.rst +++ /dev/null @@ -1,5 +0,0 @@ -Manager -======= - -.. autoclass:: landbosse.model.Manager - :members: \ No newline at end of file diff --git a/docs/doc_SitePreparationCost.rst b/docs/doc_SitePreparationCost.rst deleted file mode 100644 index d39d2a50..00000000 --- a/docs/doc_SitePreparationCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -SitePreparationCost -=================== - -.. autoclass:: landbosse.model.SitePreparationCost - :members: diff --git a/docs/doc_SubstationCost.rst b/docs/doc_SubstationCost.rst deleted file mode 100644 index 82302d6b..00000000 --- a/docs/doc_SubstationCost.rst +++ /dev/null @@ -1,5 +0,0 @@ -SubstationCost -============== - -.. autoclass:: landbosse.model.SubstationCost - :members: diff --git a/docs/doc_WeatherDelay.rst b/docs/doc_WeatherDelay.rst deleted file mode 100644 index 28222c42..00000000 --- a/docs/doc_WeatherDelay.rst +++ /dev/null @@ -1,5 +0,0 @@ -WeatherDelay -============ - -.. autoclass:: landbosse.model.WeatherDelay - :members: \ No newline at end of file diff --git a/docs/doc_WeatherWindowCSVReader.rst b/docs/doc_WeatherWindowCSVReader.rst deleted file mode 100644 index 3738f5ad..00000000 --- a/docs/doc_WeatherWindowCSVReader.rst +++ /dev/null @@ -1,5 +0,0 @@ -WeatherWindowCSVReader -====================== - -.. automodule:: landbosse.excelio.WeatherWindowCSVReader - :members: diff --git a/docs/doc_XlsxFileOperations.rst b/docs/doc_XlsxFileOperations.rst deleted file mode 100644 index 8abe77fe..00000000 --- a/docs/doc_XlsxFileOperations.rst +++ /dev/null @@ -1,5 +0,0 @@ -XlsxFileOperations -================== - -.. automodule:: landbosse.excelio.XlsxFileOperations - :members: diff --git a/docs/doc_XlsxGenerator.rst b/docs/doc_XlsxGenerator.rst deleted file mode 100644 index c2b1d85b..00000000 --- a/docs/doc_XlsxGenerator.rst +++ /dev/null @@ -1,5 +0,0 @@ -XlsxGenerator -============= - -.. automodule:: landbosse.excelio.XlsxGenerator - :members: diff --git a/docs/doc_XlsxManagerRunner.rst b/docs/doc_XlsxManagerRunner.rst deleted file mode 100644 index ad2e70ec..00000000 --- a/docs/doc_XlsxManagerRunner.rst +++ /dev/null @@ -1,5 +0,0 @@ -XlsxManagerRunner -================= - -.. autoclass:: landbosse.excelio.XlsxManagerRunner - :members: \ No newline at end of file diff --git a/docs/doc_XlsxParallelManagerRunner.rst b/docs/doc_XlsxParallelManagerRunner.rst deleted file mode 100644 index c973435c..00000000 --- a/docs/doc_XlsxParallelManagerRunner.rst +++ /dev/null @@ -1,7 +0,0 @@ -XlsxParallelManagerRunner -========================= - -.. autoclass:: landbosse.excelio.XlsxParallelManagerRunner - :members: - -.. autofunction:: landbosse.excelio.XlsxParallelManagerRunner.run_single_project diff --git a/docs/doc_XlsxReader.rst b/docs/doc_XlsxReader.rst deleted file mode 100644 index 5bc2a606..00000000 --- a/docs/doc_XlsxReader.rst +++ /dev/null @@ -1,5 +0,0 @@ -XlsxReader -========== - -.. automodule:: landbosse.excelio.XlsxReader - :members: \ No newline at end of file diff --git a/docs/doc_XlsxSerialManagerRunner.rst b/docs/doc_XlsxSerialManagerRunner.rst deleted file mode 100644 index 7cfd7077..00000000 --- a/docs/doc_XlsxSerialManagerRunner.rst +++ /dev/null @@ -1,5 +0,0 @@ -XlsxSerialManagerRunner -======================= - -.. autoclass:: landbosse.excelio.XlsxSerialManagerRunner - :members: \ No newline at end of file diff --git a/docs/doc_XlsxValidator.rst b/docs/doc_XlsxValidator.rst deleted file mode 100644 index 219b6e49..00000000 --- a/docs/doc_XlsxValidator.rst +++ /dev/null @@ -1,5 +0,0 @@ -XlsxValidator -============= - -.. automodule:: landbosse.excelio.XlsxValidator - :members: diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..b557eefc --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,3 @@ +# Examples + +Coming soon \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 7ed80f94..00000000 --- a/docs/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -LandBOSSE -========= - -This repository accompanies the report entitled "NREL’s Balance-of-System Cost Model for -Land-Based Wind" - -.. toctree:: - doc_Manager - doc_ManagementCost - doc_WeatherDelay - doc_CollectionCost - doc_SitePreparationCost - doc_FoundationCost - doc_ErectionCost - doc_SubstationCost - doc_GridConnectionCost - doc_XlsxFileOperations - doc_XlsxValidator - doc_XlsxReader - doc_XlsxGenerator - doc_XlsxManagerRunner - doc_XlsxSerialManagerRunner - doc_XlsxParallelManagerRunner - doc_WeatherWindowCSVReader diff --git a/docs/intro.md b/docs/intro.md new file mode 100644 index 00000000..2b26499f --- /dev/null +++ b/docs/intro.md @@ -0,0 +1,2 @@ +:::{include} ../README.md +::: \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 7893348a..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd diff --git a/docs/references.bib b/docs/references.bib new file mode 100644 index 00000000..783ec6aa --- /dev/null +++ b/docs/references.bib @@ -0,0 +1,56 @@ +--- +--- + +@inproceedings{holdgraf_evidence_2014, + address = {Brisbane, Australia, Australia}, + title = {Evidence for {Predictive} {Coding} in {Human} {Auditory} {Cortex}}, + booktitle = {International {Conference} on {Cognitive} {Neuroscience}}, + publisher = {Frontiers in Neuroscience}, + author = {Holdgraf, Christopher Ramsay and de Heer, Wendy and Pasley, Brian N. and Knight, Robert T.}, + year = {2014} +} + +@article{holdgraf_rapid_2016, + title = {Rapid tuning shifts in human auditory cortex enhance speech intelligibility}, + volume = {7}, + issn = {2041-1723}, + url = {http://www.nature.com/doifinder/10.1038/ncomms13654}, + doi = {10.1038/ncomms13654}, + number = {May}, + journal = {Nature Communications}, + author = {Holdgraf, Christopher Ramsay and de Heer, Wendy and Pasley, Brian N. and Rieger, Jochem W. and Crone, Nathan and Lin, Jack J. and Knight, Robert T. and Theunissen, Frédéric E.}, + year = {2016}, + pages = {13654}, + file = {Holdgraf et al. - 2016 - Rapid tuning shifts in human auditory cortex enhance speech intelligibility.pdf:C\:\\Users\\chold\\Zotero\\storage\\MDQP3JWE\\Holdgraf et al. - 2016 - Rapid tuning shifts in human auditory cortex enhance speech intelligibility.pdf:application/pdf} +} + +@inproceedings{holdgraf_portable_2017, + title = {Portable learning environments for hands-on computational instruction using container-and cloud-based technology to teach data science}, + volume = {Part F1287}, + isbn = {978-1-4503-5272-7}, + doi = {10.1145/3093338.3093370}, + abstract = {© 2017 ACM. There is an increasing interest in learning outside of the traditional classroom setting. This is especially true for topics covering computational tools and data science, as both are challenging to incorporate in the standard curriculum. These atypical learning environments offer new opportunities for teaching, particularly when it comes to combining conceptual knowledge with hands-on experience/expertise with methods and skills. Advances in cloud computing and containerized environments provide an attractive opportunity to improve the effciency and ease with which students can learn. This manuscript details recent advances towards using commonly-Available cloud computing services and advanced cyberinfrastructure support for improving the learning experience in bootcamp-style events. We cover the benets (and challenges) of using a server hosted remotely instead of relying on student laptops, discuss the technology that was used in order to make this possible, and give suggestions for how others could implement and improve upon this model for pedagogy and reproducibility.}, + booktitle = {{ACM} {International} {Conference} {Proceeding} {Series}}, + author = {Holdgraf, Christopher Ramsay and Culich, A. and Rokem, A. and Deniz, F. and Alegro, M. and Ushizima, D.}, + year = {2017}, + keywords = {Teaching, Bootcamps, Cloud computing, Data science, Docker, Pedagogy} +} + +@article{holdgraf_encoding_2017, + title = {Encoding and decoding models in cognitive electrophysiology}, + volume = {11}, + issn = {16625137}, + doi = {10.3389/fnsys.2017.00061}, + abstract = {© 2017 Holdgraf, Rieger, Micheli, Martin, Knight and Theunissen. Cognitive neuroscience has seen rapid growth in the size and complexity of data recorded from the human brain as well as in the computational tools available to analyze this data. This data explosion has resulted in an increased use of multivariate, model-based methods for asking neuroscience questions, allowing scientists to investigate multiple hypotheses with a single dataset, to use complex, time-varying stimuli, and to study the human brain under more naturalistic conditions. These tools come in the form of “Encoding” models, in which stimulus features are used to model brain activity, and “Decoding” models, in which neural features are used to generated a stimulus output. Here we review the current state of encoding and decoding models in cognitive electrophysiology and provide a practical guide toward conducting experiments and analyses in this emerging field. Our examples focus on using linear models in the study of human language and audition. We show how to calculate auditory receptive fields from natural sounds as well as how to decode neural recordings to predict speech. The paper aims to be a useful tutorial to these approaches, and a practical introduction to using machine learning and applied statistics to build models of neural activity. The data analytic approaches we discuss may also be applied to other sensory modalities, motor systems, and cognitive systems, and we cover some examples in these areas. In addition, a collection of Jupyter notebooks is publicly available as a complement to the material covered in this paper, providing code examples and tutorials for predictive modeling in python. The aimis to provide a practical understanding of predictivemodeling of human brain data and to propose best-practices in conducting these analyses.}, + journal = {Frontiers in Systems Neuroscience}, + author = {Holdgraf, Christopher Ramsay and Rieger, J.W. and Micheli, C. and Martin, S. and Knight, R.T. and Theunissen, F.E.}, + year = {2017}, + keywords = {Decoding models, Encoding models, Electrocorticography (ECoG), Electrophysiology/evoked potentials, Machine learning applied to neuroscience, Natural stimuli, Predictive modeling, Tutorials} +} + +@book{ruby, + title = {The Ruby Programming Language}, + author = {Flanagan, David and Matsumoto, Yukihiro}, + year = {2008}, + publisher = {O'Reilly Media} +} diff --git a/installation_instructions/01_windows_anaconda_prompt_menu.png b/installation_instructions/01_windows_anaconda_prompt_menu.png deleted file mode 100644 index 16943553..00000000 Binary files a/installation_instructions/01_windows_anaconda_prompt_menu.png and /dev/null differ diff --git a/installation_instructions/02_make_folders.png b/installation_instructions/02_make_folders.png deleted file mode 100644 index ea442a75..00000000 Binary files a/installation_instructions/02_make_folders.png and /dev/null differ diff --git a/installation_instructions/03_clone_the_repo.png b/installation_instructions/03_clone_the_repo.png deleted file mode 100644 index a67b3d3a..00000000 Binary files a/installation_instructions/03_clone_the_repo.png and /dev/null differ diff --git a/installation_instructions/05_download_zip.png b/installation_instructions/05_download_zip.png deleted file mode 100644 index 144fefd3..00000000 Binary files a/installation_instructions/05_download_zip.png and /dev/null differ diff --git a/installation_instructions/06_landbosse_dev.png b/installation_instructions/06_landbosse_dev.png deleted file mode 100644 index 219ec17d..00000000 Binary files a/installation_instructions/06_landbosse_dev.png and /dev/null differ diff --git a/installation_instructions/11_copy_project_input_template.png b/installation_instructions/11_copy_project_input_template.png deleted file mode 100644 index 3e6614a1..00000000 Binary files a/installation_instructions/11_copy_project_input_template.png and /dev/null differ diff --git a/installation_instructions/12_paste_project_input_template.png b/installation_instructions/12_paste_project_input_template.png deleted file mode 100644 index bbcf0022..00000000 Binary files a/installation_instructions/12_paste_project_input_template.png and /dev/null differ diff --git a/installation_instructions/13_done_pasting.png b/installation_instructions/13_done_pasting.png deleted file mode 100644 index 70372e43..00000000 Binary files a/installation_instructions/13_done_pasting.png and /dev/null differ diff --git a/installation_instructions/macos_developer.md b/installation_instructions/macos_developer.md deleted file mode 100644 index 066aa725..00000000 --- a/installation_instructions/macos_developer.md +++ /dev/null @@ -1,203 +0,0 @@ -# macOS developer installation guide - -## Audiences - -Both end users and developers have a similar installation experience of LandBOSSE. Developers just have a couple more steps that are at the bottom of this document and are marked as such. - -## LandBOSSE is a command line program - -In its current version, LandBOSSE is a command line program. You access it from terminal. - -## Anaconda Installation - -This installation guide assumes you have a Python 3.7 or later version of the Anaconda distribution of Python installed. If you aren't using Anaconda you can modify these instructions, but those modifications aren't explained here. - -[Download the latest macOS version of Anaconda with Anconda 3.7 or later](https://www.anaconda.com/distribution/) - -Note: You will need to quit and restart your command line terminal for your Anaconda installation to be enabled. - -LandBOSSE doesn't support Python 2.x. - -## Step 1a: Open the command prompt with the terminal - -In finder, open the `Applications` folder and find the `Utilities` subfolder. Click on the `Terminal` app to start the command prompt. - -## Step 1b: Create a folder structure - -Somewhere on your computer create a directory structure for the LandBOSSE source code, input files and output files. For example if you want it on your desktop, from your terminal type the following: - -``` -mkdir ~/Desktop/landbosse -mkdir ~/Desktop/landbosse/input -mkdir ~/Desktop/landbosse/output -cd ~/Desktop/landbosse -``` - -You can put the folders somewhere else if you want. Just remember where they go when you use environment variables in this documentation. This directory structure will be referenced for all future commands in this document. - -## Step 2: Fork and clone this repository - -Forking and cloning are the two steps to installing the LandBOSSE code on your computer so you can you can run it. - -### 2a. If you have forked and clone before, and use `git` on the command line. - -1. Create your own fork of LandBOSSE under your own account. -1. Then clone with commands similar to `git clone https://github.com/YOUR USERNAME/LandBOSSE.git`. - -Now go to step 3. - -### 2b. If you have NOT forked and/or cloned before, and want to use the command line, please read this. - -1. Open your command prompt. -1. Install the `git` command line tool `xcode-select --install` -1. GitHub has some good documentation on learning about forking and cloning at [https://help.github.com/en/articles/fork-a-repo](https://help.github.com/en/articles/fork-a-repo) - -After you've read the documentation, please return to [https://github.com/WISDEM/LandBOSSE](https://github.com/WISDEM/LandBOSSE). From there, fork the LandBOSSE repository and run the following commands: - -``` -cd ~/Desktop/landbosse -git clone https://github.com/YOUR USERNAME/LandBOSSE.git -cd LandBOSSE -``` - -Substitute `YOUR USERNAME` with the username or organization to which you forked your copy of LandBOSSE. - -### 2c. If you use another tool other than command line `git`, follow these steps: - -Using your software, make sure that you clone into the `cd ~/Desktop/landbosse` folder and follow the directions in this tutorial. - -## Step 3: Set up a virtual environment -Setup a virtual environment for all your LandBOSSE dependencies. - -``` -conda create -n LandBOSSE python=3.7 -conda activate LandBOSSE -``` - -All the commands in this README are meant to be executed within a virtual environment and within the `LandBOSSE` folder. - -## Step 4: Install first set of packages - -In order to run the code, modify the code, build the documentation and run the tests, you will neeed to install a few packages with conda. Type the following command to do so: - -``` -conda install pytest sphinx sphinx_rtd_theme -``` - -## Step 5: Install LandBOSSE itself, along with more packages - -Install the package *for development* with the following command: - -``` -cd ~/Desktop/landbosse/LandBOSSE -pip install -e . -``` - -By installing it in developer mode with `pip` you have two benefits: - -1. It can be uninstalled with `pip uninstall NREL-landbosse` (you don't need to uninstall it right now) -1. You can update the source code with re-installing the package because `pip` uses symbolic links (aka symlinks) to reference your source code directory. - -## Step 6: Copy your input data - -Copy the template file out to the `landbosse/input` directory that you created in Step 1. You should have a `projects_list.xlsx` file and a `project_data` subfolder in your input directory. - -## Step 7: Environment variables - -Because of the numerous files needed for execution of projects and the numerous timestamped output files, LandBOSSE uses environment variables to track folders where these files are stored. The following variables must be present in every execution of LandBOSSE - -1. `LANDBOSSE_INPUT_DIR`: The absolute path to the folder containing `projects_list.xlsx` file and the `project_data` folder. -1. `LANDBOSSE_OUTPUT_DIR`: The absolute path to the folder where the output files will be placed. - -If you want to find out more about environment variables in general, [you can optionally read about environment variables on Wikipedia](https://en.wikipedia.org/wiki/Environment_variable). - -You can set these environment variables with: - -1. `export LANDBOSSE_INPUT_DIR=???` and `export LANDBOSSE_OUTPUT_DIR=???` where `???` is where you need the environment variable to point. -1. In your `.bashrc` or `.zshrc` files -1. In your IDE, if you are a developer and use an IDE -1. On the same command line you execute LandBOSSE. - -The first three are outside the scope of this document. The fourth, however, is how we will execute LandBOSSE in the next step. - -## Step 8: Copy and modify template input files to input folder - -In the `LandBOSSE` directory you will find a folder named `project_input_template`. Copy (do not move) the contents of this folder into the `inputs` folder you created and specified in Steps 3 and 7. Retain the folder structure in `project_input_template`. - -The file named `projects_list.xlsx` must keep the same name. The names of the project data files in the `project_data` folder must match the project names in `projects_list.xlsx`. - -## Step 9: Execute LandBOSSE - -Suppose that you have created the directory structure on your desktop as mentioned above in step 2 "Create a folder structure". You can set the environment variables and execute LandBOSSE with a couple easy commands: - -``` -cd ~/Desktop/landbosse/LandBOSSE -python main.py -i ~/Desktop/landbosse/input -o ~/Desktop/landbosse/output -``` - -The file will be produced with a filename like: - -`landbosse-output-2019-6-18-13-8-2.xlsx` - -Where the timestamp is in the format of *year-month-day-hour-minute-second* - -## Step 10: Exiting your development environment -When you are done with your development work, type the following command: - -``` -conda deactivate -``` - -That will exit your virtual environment so that you can run other Python projects. - -## *Developers step 11: Build documentation* -This step is for software developers. - -You can automatically generate documentation from docstrings with Sphinx and autodoc. Whenever you update the `.rst` files or the docstrings in the `.py` files, you need to rebuild the documentation. From the `docs/` folder of this repository, run the following commands: - -``` -make clean -make html -``` - -After you run the command, you can open the documentation at: - -``` -docs/_build/html/index.html -``` - -## *Developers step 13: Run tests* -This step is for software developers. - -LandBOSSE ships with a number of black box tests. These tests are intended to make sure that each module can execute without throwing exceptions. - -To run these tests. change thw directory to the root of the repository. Ensure that your virtual environment is activated. Then, at the command prompt type the following command: - -``` -pytest -``` - -When all tests pass, output will be similar to the following: - -``` -============================ test session starts ============================= -platform darwin -- Python 3.7.3, pytest-4.6.2, py-1.8.0, pluggy-0.12.0 -rootdir: /XYZ/LandBOSSE -collected 29 items - -landbosse/tests/model/test_CollectionCost.py ..... [ 17%] -landbosse/tests/model/test_DevelopmentCost.py . [ 20%] -landbosse/tests/model/test_ErectionCost.py . [ 24%] -landbosse/tests/model/test_FoundationCost.py . [ 27%] -landbosse/tests/model/test_ManagementCost.py ........... [ 65%] -landbosse/tests/model/test_RoadsCost.py ..... [ 82%] -landbosse/tests/model/test_SubstationCost.py . [ 86%] -landbosse/tests/model/test_TransmissionCost.py . [ 89%] -landbosse/tests/model/test_WeatherDelay.py ... [100%] - -========================= 29 passed in 8.63 seconds ========================== -``` - -Where `XYZ`, as shown above, will be substituted with the path to your LandBOSSE repository. - -If there are failures, the resulting exceptions will be displayed for further inspection. diff --git a/installation_instructions/normal-operation-flowchart.png b/installation_instructions/normal-operation-flowchart.png deleted file mode 100644 index 1ab72263..00000000 Binary files a/installation_instructions/normal-operation-flowchart.png and /dev/null differ diff --git a/installation_instructions/operation_and_folder_structure.md b/installation_instructions/operation_and_folder_structure.md deleted file mode 100644 index f468a350..00000000 --- a/installation_instructions/operation_and_folder_structure.md +++ /dev/null @@ -1,123 +0,0 @@ -# Input and Output File Structure - -LandBOSSE reads multiple files in a folder structure as an input and produces multiple files in a folder structure as an output. To find these files, LandBOSSE looks at its command line or to environment variables for the locations. This document explains how to set up the inputs and outputs. - -## Input file structure - -The input is comprised of two parts: - -+ Project data, which are `.xlsx` spreadsheets that contain sheets of data about components, equipment, crews and so on. There is always at least one, and maybe more, files of project data. - -+ A project list which combines parameters that define projects with reference to the project data those projects use. There is only one file that has the project list. - -There is a many-to-many correspondence of projects to project data files: multiple projects can reference the same project data. - -``` -| -|--- project_list.xlsx -|---| - |--- project_data_1.xlsx - |--- project_data_2.xlsx - |--- ... - |--- project_data_N.xlsx -``` - -There can be other files in the input directory, but LandBOSSE will ignore the extra files if they are not needed. - -## Output file structure - -The output file structure is comprised of two parts: - -+ The actual data output from the model in the form of an `.xlsx` spreadsheet. - -+ All the input files that created the output data. - -An output folder structure can be reused as an input into LandBOSSE to reproduce results from, or modify inputs into, a particular run of the LandBOSSE model. - -When LandBOSSE runs, you give it the path to an output folder. In turn, LandBOSSE puts a timestamped subfolder into the parent folder you specify and places all the output files into that folder. As you run LandBOSSE successive time with the same output folder, you will get an output folder that looks like this: - -``` -| -|--- landbosse-YEAR-MONTH-DAY-HOUR-MINUTE-SECOND -|---| -| |--- landbosse-output.xlsx -| |--- project_list.xlsx -| |--- project_data -| |--- project_data_1.xlsx -| |--- project_data_2.xlsx -| |--- etc. -| -|--- landbosse-YEAR-MONTH-DAY-HOUR-MINUTE-SECOND -|---| - |--- landbosse-output.xlsx - |--- project_list.xlsx - |--- project_data - |--- project_data_1.xlsx - |--- project_data_2.xlsx - |--- etc. -``` - -At the top level are directories timestamped with the date and time the model executed. - -## Specifying files during LandBOSSE runs - -The easiest way to specify paths to LandBOSSE folders is on the command line, as shown below. - -``` -python main.py --input PATH_TO_INPUT_FOLDER --output PATH_TO_OUTPUT_FOLDER -``` - -If you prefer shorter command lines, you have the following option: - -``` -python main.py -i PATH_TO_INPUT_FOLDER -o PATH_TO_OUTPUT_FOLDER -``` - -If you don't want to set the paths every time you execute LandBOSSE, you can set the `LANDBOSSE_INPUT_DIR` and `LANDBOSSE_OUTPUT_DIR` environment variables, but that is not necessary. - -Here's a flowchart of how the model gathers and copies input data during normal operation: - -![flowchart of validation process](normal-operation-flowchart.png) - -## Validating model output - -Recall that a LandBOSSE output folder can be used as an input folder. This means that every output folder is a record of inputs, with their associated outputs, that have been created by the LandBOSSE model at a certain point in time. As software development of the model takes place, software defects may be introduced. - -The validation process protects against these software defects. The idea is simple: If you take an output folder from a time when you **know that the code operated correctly**, you can attempt to recreate those earlier results with another version of the code. If you can reproduce the results, that means the model is still functioning normally. If you don't reproduce the results, that means the model failed and needs to be fixed. - -Here is a flowchart of the validation process: - -![flowchart of validation process](validation-flowchart.png) - -First, the model runs. However, instead of the final output being written as a file, it is compared to the previously calculated LandBOSSE output. If the outputs compare successfully, the model is working the same as it did at the previous point time when it was verified to be working properly. - -The output data previously created and known to be good are known as the **expected** data. Data being validated are called **actual** data. To run a validation, you need three things: - -+ Expected output data, -+ Input data that created that expected output data, -+ Actual output data, generated from these input data, to compare against the expected output data. - -For validating LandBOSSE, the input data are stored in the same folder structure as you would use for input data for a normal LandBOSSE run, but with an additional file called `landbosse-expected-validation-data.xlsx`, which is the output file generated from a version of LandBOSSE known to operate correctly. - -``` -| -|--- project_list.xlsx -|--- landbosse-expected-validation-data.xlsx -|---| -| |--- project_data_1.xlsx -| |--- project_data_2.xlsx -| |--- ... -| |--- project_data_N.xlsx -| -|--- landbosse-validation-result.xlsx -``` - -*Note: The last fie is generated by LandBOSSE during validation. You don't need to supply it ahead of time.* - -To validate the model, you would run the following command. - -``` -python main.py --input PATH_TO_FOLDER_WITH_VALIDATION_DATA --output PATH_TO_YOUR_OUTPUT_FOLDER --validate -``` - -This command will run the model to obtain the actual data and will create the `landbosse-validation-result.xlsx`. It will write the validation diff --git a/installation_instructions/validation-flowchart.png b/installation_instructions/validation-flowchart.png deleted file mode 100644 index e5be53cd..00000000 Binary files a/installation_instructions/validation-flowchart.png and /dev/null differ diff --git a/installation_instructions/windows_end_user.md b/installation_instructions/windows_end_user.md deleted file mode 100644 index 92467076..00000000 --- a/installation_instructions/windows_end_user.md +++ /dev/null @@ -1,105 +0,0 @@ -# LandBOSSE Installation - -## Windows Installation for End Users - -### Step 1: Install Anaconda - -You will need the Anaconda distribution of Python. You need the distribution with **Python 3.7** or higher. - -[https://www.anaconda.com/distribution/](https://www.anaconda.com/distribution/) - -### Step 2: Launch the Anaconda Prompt - -LandBOSSE is a command line tool. You will need to launch the Anaconda prompt (either "Anaconda Prompt" or "Anaconda Powershell Prompt" will work.) Search your start menu for "Anaconda3" and you should get a folder ike the one below which lets you select the Anaconda prompt. As you type commands, you should not get error messages. This is indicated by *no messages* after you type the command. - -![Anaconda prompt menu selection](01_windows_anaconda_prompt_menu.png) - -### Step 3: Create three data folders - -You need 3 folders on your desktop for LandBOSSE data. You can certainly put them in a place other than your desktop, but you will need to modify the commands below if you do. - -Your command prompt will look something like the following: - -![Command prompt for making folders](02_make_folders.png) - -This is what you should type: - -``` -md \Users\%USERNAME%\Desktop\landbosse -md \Users\%USERNAME%\Desktop\landbosse\input -md \Users\%USERNAME%\Desktop\landbosse\output -``` - -### Step 4: Get the source code - -If you are familiar with `git` and GitHub and have a workflow to use to obtain the source code, please skip to the next step. - -However, if you are unfamiliar with `git` and GitHub you can simply download the `.zip` file. Find the main GitHub page for this project [https://github.com/WISDEM/LandBOSSE](https://github.com/WISDEM/LandBOSSE). - -![Clone the GitHub repo](03_clone_the_repo.png) - -Click on "Download ZIP" to download the `.zip` file. - -### Step 5: Get the source code ready - -Open the `.zip` file. Copy the single directory within it to the `landbosse` folder on the desktop. Rename the directory to `LandBOSSE-dev` - -Your first step upon opening the `.zip` will be this: - -![Open the source code zip](05_download_zip.png) - -Move the file into position like this. - -![The landbosse dev directory](06_landbosse_dev.png) - -This is the directory configuration you need to run LandBOSSE. - -### Step 6: A word of caution about input files - -Input files shouldn't be placed in the LandBOSSE source code directory. *This creates a risk that proprietary input data will become visible in a source code repository.* This risk is mitigated by using the folder structure you just created above. - -### Step 7: Copy your data into the input folder - -Now you can copy the template input files into the LandBOSSE input folder. Navigate to the `project_input_template` folder in the LandBOSSE source directory, as shown below. - -![Copy LandBOSSE input template](11_copy_project_input_template.png) - -Following this example, the project input template lives in the `C:\Users\YOUR USERNAME\Desktop\landbosse\LandBOSSE\project_input_template` folder. Substitute `YOUR USERNAME` with the username you use to log in to your computer. - -Paste these files into the input folder you made earlier: - -![Paste the input template files](12_paste_project_input_template.png) - -Your result will look like this when you are done: - -![done pasting](13_done_pasting.png) - -Note: Depending on the version of LandBOSSE, you may have more files copied into the input folder. As long as you copy over all the input files into the destination folder, LandBOSSE will find its input files. - -### Step 8: Install the LandBOSSE package - -The command should result in a message that begins Then install LandBOSSE itself: - -``` -cd \Users\%USERNAME%\Desktop\landbosse\LandBOSSE-master -pip install -e . -``` - -## Step 9: Copy and modify template input files to input folder - -In the `LandBOSSE` directory you will find a folder named `project_input_template`. Copy (do not move) the contents of this folder into the `inputs` folder you created and specified in Steps 3 and 7. Retain the folder structure in `project_input_template`. - -The file named `projects_list.xlsx` must keep the same name. The names of the project data files in the `project_data` folder must match the project names in `projects_list.xlsx`. - -### Step 10: Run LandBOSSE - -Navigate back to where you installed LandBOSSE (in case you have navigated away) and run LandBOSSE by typing the following two commands: - -``` -cd \Users\%USERNAME%\Desktop\landbosse\LandBOSSE-master\ -python main.py -i \Users\%USERNAME%\Desktop\landbosse\input -o \Users\%USERNAME%\Desktop\landbosse\output -``` - -### Step 11: Examine the results - -Your output is in the `output` directory of your landbosse directory! diff --git a/landbosse/__init__.py b/landbosse/__init__.py index 5b47d4b0..45acc53b 100644 --- a/landbosse/__init__.py +++ b/landbosse/__init__.py @@ -1,2 +1,2 @@ -__version__ = "2.6.1" +__version__ = "2.6.2" diff --git a/landbosse/excelio/WeatherWindowCSVReader.py b/landbosse/excelio/WeatherWindowCSVReader.py index d2f61152..8057aa02 100644 --- a/landbosse/excelio/WeatherWindowCSVReader.py +++ b/landbosse/excelio/WeatherWindowCSVReader.py @@ -32,7 +32,11 @@ def read_weather_window(weather_data, local_timezone='America/Denver'): The .csv should have the first 5 columns of: - Date, Temp C, Pressure atm, Direction deg, Speed m per s + * Date + * Temp C + * Pressure atm + * Direction deg + * Speed m per s Other columns are ignored, headers are ignored and the first four lines are skipped. Dates in this file are assumed to be @@ -45,31 +49,17 @@ def read_weather_window(weather_data, local_timezone='America/Denver'): The columns returned in the dataframe are: - 'Date UTC': The date and time in UTC of the measurements in that row. - - 'Date': The date, localized to the timezone specified in the - local_timezone parameter. See parameter list below. - - 'Year': An integer of the year of the local time zone date - - 'Month': An integer of the month of the local time zone date - - 'Day': An integer of the day of the local time zone date - - 'Hour': An integer of the hour of the local time zone date - - 'Time window': If the integer hour is between 8 and 18 inclusive, - this is 'normal'. For hours outside of that range, this is - 'long'. - - 'Season': Season of the year. Months 1, 2, 3 are winter; months 4, 5, 6 - are spring; months 7, 8, 9 are summer; months 10, 11, 12 are fall. - - 'Pressure atm': Air pressure in atm. - - 'Direction deg': Wind direction in degrees. - - 'Speed m per s': Wind speed in meters per second. + * 'Date UTC': The date and time in UTC of the measurements in that row. + * 'Date': The date, localized to the timezone specified in the local_timezone parameter. See parameter list below. + * 'Year': An integer of the year of the local time zone date + * 'Month': An integer of the month of the local time zone date + * 'Day': An integer of the day of the local time zone date + * 'Hour': An integer of the hour of the local time zone date + * 'Time window': If the integer hour is between 8 and 18 inclusive, this is 'normal'. For hours outside of that range, this is 'long'. + * 'Season': Season of the year. Months 1, 2, 3 are winter; months 4, 5, 6 are spring; months 7, 8, 9 are summer; months 10, 11, 12 are fall. + * 'Pressure atm': Air pressure in atm. + * 'Direction deg': Wind direction in degrees. + * 'Speed m per s': Wind speed in meters per second. Parameters ---------- diff --git a/landbosse/excelio/XlsxGenerator.py b/landbosse/excelio/XlsxGenerator.py index b0af8730..25c7c454 100644 --- a/landbosse/excelio/XlsxGenerator.py +++ b/landbosse/excelio/XlsxGenerator.py @@ -169,7 +169,13 @@ def tab_details(self, rows): This writes a detailed outputs tab. It takes a list of dictionaries as the parameters and in each of those dictionaries it looks at the keys: - ['project_id', 'module', 'type', 'variable_df_key_col_name', 'unit', 'numeric value', 'non_numeric_value'] + * 'project_id' + * 'module' + * 'type' + * 'variable_df_key_col_name' + * 'unit' + * 'numeric value' + * 'non_numeric_value' The values of each of those keys become each cell in the row. diff --git a/landbosse/excelio/XlsxReader.py b/landbosse/excelio/XlsxReader.py index bc6cf828..a8cf4b07 100644 --- a/landbosse/excelio/XlsxReader.py +++ b/landbosse/excelio/XlsxReader.py @@ -62,28 +62,32 @@ def create_parametric_value_list(self, parametric_list): """ Assuming we have a "Parametric list" sheet/dataframe like the following - | Project ID | Dataframe name | Row name | Column name | Start | End | Step - |------------|----------------------|----------|-------------|-------|-----|------ - | project1 | alpha | fizz | buzz | 0 | 12 | 6 - | project1 | beta | foo | bar | 0 | 12 | 6 - | project2 | gamma | dogs | cats | 21 | 27 | 3 + =========== ============== ======== =========== ===== === ==== + Project ID Dataframe name Row name Column name Start End Step + =========== ============== ======== =========== ===== === ==== + project1 alpha fizz buzz 0 12 6 + project1 beta foo bar 0 12 6 + project2 gamma dogs cats 21 27 3 + =========== ============== ======== =========== ===== === ==== Translate this data frame into a data frame of the following format: - | Project ID | Serial | alpha/fizz/buzz | beta/foo/bar | gamma/dogs/cats - |------------|-------------|-----------------|--------------|----------------| - | project1 | project1_00 | 0 | 0 | NaN | - | project1 | project1_01 | 0 | 6 | NaN | - | project1 | project1_02 | 0 | 12 | NaN | - | project1 | project1_03 | 6 | 0 | NaN | - | project1 | project1_04 | 6 | 6 | NaN | - | project1 | project1_05 | 6 | 12 | NaN | - | project1 | project1_06 | 12 | 0 | NaN | - | project1 | project1_07 | 12 | 6 | NaN | - | project1 | project1_08 | 12 | 12 | NaN | - | project2 | project2_09 | NaN | NaN | 21 | - | project2 | project2_10 | NaN | NaN | 24 | - | project2 | project2_11 | NaN | NaN | 27 | + ========== =========== =============== ============ =============== + Project ID Serial alpha/fizz/buzz beta/foo/bar gamma/dogs/cats + ========== =========== =============== ============ =============== + project1 project1_00 0 0 NaN + project1 project1_01 0 6 NaN + project1 project1_02 0 12 NaN + project1 project1_03 6 0 NaN + project1 project1_04 6 6 NaN + project1 project1_05 6 12 NaN + project1 project1_06 12 0 NaN + project1 project1_07 12 6 NaN + project1 project1_08 12 12 NaN + project2 project2_09 NaN NaN 21 + project2 project2_10 NaN NaN 24 + project2 project2_11 NaN NaN 27 + ========== =========== =============== ============ =============== Here NaN is not an error. It is the normal way Pandas handles empty cells It means that, for a particular project, @@ -170,50 +174,56 @@ def outer_join_projects_to_parametric_values(self, project_list, parametric_valu Consider the dataframe we made in create_parametric_value_list. Call it parametric_value_list: - | Project ID | Project ID with serial | alpha/fizz/buzz | beta/foo/bar | gamma/dogs/cats - |------------|-----------------------------|-----------------|--------------|----------------| - | project1 | project1_00 | 0 | 0 | NaN | - | project1 | project1_01 | 0 | 6 | NaN | - | project1 | project1_02 | 0 | 12 | NaN | - | project1 | project1_03 | 6 | 0 | NaN | - | project1 | project1_04 | 6 | 6 | NaN | - | project1 | project1_05 | 6 | 12 | NaN | - | project1 | project1_06 | 12 | 0 | NaN | - | project1 | project1_07 | 12 | 6 | NaN | - | project1 | project1_08 | 12 | 12 | NaN | - | project2 | project2_09 | NaN | NaN | 21 | - | project2 | project2_10 | NaN | NaN | 24 | - | project2 | project2_11 | NaN | NaN | 27 | + ========== ====================== =============== ============ =============== + Project ID Project ID with serial alpha/fizz/buzz beta/foo/bar gamma/dogs/cats + ========== ====================== =============== ============ =============== + project1 project1_00 0 0 NaN + project1 project1_01 0 6 NaN + project1 project1_02 0 12 NaN + project1 project1_03 6 0 NaN + project1 project1_04 6 6 NaN + project1 project1_05 6 12 NaN + project1 project1_06 12 0 NaN + project1 project1_07 12 6 NaN + project1 project1_08 12 12 NaN + project2 project2_09 NaN NaN 21 + project2 project2_10 NaN NaN 24 + project2 project2_11 NaN NaN 27 + ========== ====================== =============== ============ =============== Now consider that we have the following project list data frame called project_list: - Project ID | Project data file | Total project construction time months | ... - -----------|-------------------|----------------------------------------|--- - project1 | project1_data | 9 | ... - project2 | project2_data | 9 | ... - project3 | project3_data | 9 | ... + ========== ================= ====================================== === + Project ID Project data file Total project construction time months ... + ========== ================= ====================================== === + project1 project1_data 9 ... + project2 project2_data 9 ... + project3 project3_data 9 ... + ========== ================= ====================================== === OUTER join project_list with parametric_value_list such that you get the following data frame. The outer join ensures that even projects that do not have parametrics attached to them find their way to the list of projects to be executed. - | Project ID | Project ID with serial | alpha/fizz/buzz | beta/foo/bar | gamma/dogs/cats Project data file | ... - |------------|-----------------------------|-----------------|--------------|----------------|-------------------| ... - | project1 | project1_00 | 0 | 0 | NaN | project1_data | ... - | project1 | project1_01 | 0 | 6 | NaN | project1_data | ... - | project1 | project1_02 | 0 | 12 | NaN | project1_data | ... - | project1 | project1_03 | 6 | 0 | NaN | project1_data | ... - | project1 | project1_04 | 6 | 6 | NaN | project1_data | ... - | project1 | project1_05 | 6 | 12 | NaN | project1_data | ... - | project1 | project1_06 | 12 | 0 | NaN | project1_data | ... - | project1 | project1_07 | 12 | 6 | NaN | project1_data | ... - | project1 | project1_08 | 12 | 12 | NaN | project1_data | ... - | project2 | project2_09 | NaN | NaN | 21 | project2_data | ... - | project2 | project2_10 | NaN | NaN | 24 | project2_data | ... - | project2 | project2_11 | NaN | NaN | 27 | project2_data | ... - | project3 | NaN | NaN | NaN | NaN | project3_data | ... + ========== ====================== =============== ============ =============== ================= + Project ID Project ID with serial alpha/fizz/buzz beta/foo/bar gamma/dogs/cats Project data file + ========== ====================== =============== ============ =============== ================= + project1 project1_00 0 0 NaN project1_data + project1 project1_01 0 6 NaN project1_data + project1 project1_02 0 12 NaN project1_data + project1 project1_03 6 0 NaN project1_data + project1 project1_04 6 6 NaN project1_data + project1 project1_05 6 12 NaN project1_data + project1 project1_06 12 0 NaN project1_data + project1 project1_07 12 6 NaN project1_data + project1 project1_08 12 12 NaN project1_data + project2 project2_09 NaN NaN 21 project2_data + project2 project2_10 NaN NaN 24 project2_data + project2 project2_11 NaN NaN 27 project2_data + project3 NaN NaN NaN NaN project3_data + ========== ====================== =============== ============ =============== ================= This data frame is in place to run with a modified project manager runner. The modification to the runner will run modifications to the diff --git a/landbosse/model/CollectionCost.py b/landbosse/model/CollectionCost.py index 50f2db10..0d27fc52 100644 --- a/landbosse/model/CollectionCost.py +++ b/landbosse/model/CollectionCost.py @@ -1,15 +1,7 @@ """ -**CollectionCost.py** -- Created by Matt Shields for Offshore BOS -- Refactored by Parangat Bhaskar for LandBOSSE - -NREL - 05/31/2019 - -This module consists of two classes: - -- The first class in this module is the parent class Cable, with a sublass Array that inherits from Cable - -- The second class is the ArraySystem class that instantiates the Array class and determines the wind farm layout and calculates total collection system cost +Originally created for ORBIT and refactored for LandBOSSE. This module consists of two cable +classes: ``Cable`` and a subclass, ``Array``. These are combined to create the ``ArraySystem`` that +determines the wind farm layout and calculates total collection system cost. """ import math @@ -27,33 +19,33 @@ class Cable: Create an instance of Cable (either array or export) - Parameters - --------- - cable_specs : dict - Dictionary containing cable specifications - line_frequency_hz : int - Additional user inputs - - Returns - ------- - current_capacity : float - Cable current rating at 1m burial depth, Amps - rated_voltage : float - Cable rated voltage, kV - ac_resistance : float - Cable resistance for AC current, Ohms/km - inductance : float - Cable inductance, mH/km - capacitance : float - Cable capacitance, nF/km - cost : int - Cable cost, $US/km - char_impedance : float - Characteristic impedance of equivalent cable circuit, Ohms - power_factor : float - Power factor of AC current in cable (nondim) - cable_power : float - Maximum 3-phase power dissipated in cable, MW + Parameters + --------- + cable_specs : dict + Dictionary containing cable specifications + line_frequency_hz : int + Additional user inputs + + Returns + ------- + current_capacity : float + Cable current rating at 1m burial depth, Amps + rated_voltage : float + Cable rated voltage, kV + ac_resistance : float + Cable resistance for AC current, Ohms/km + inductance : float + Cable inductance, mH/km + capacitance : float + Cable capacitance, nF/km + cost : int + Cable cost, $US/km + char_impedance : float + Characteristic impedance of equivalent cable circuit, Ohms + power_factor : float + Power factor of AC current in cable (nondim) + cable_power : float + Maximum 3-phase power dissipated in cable, MW """ @@ -130,16 +122,12 @@ def __init__(self, cable_specs, addl_inputs): Dictionary containing following cable specifications: - turbine_rating_MW - - upstream_turb - - turbine_spacing_rotor_diameters - - rotor_diameter_m - + addl_inputs : dict - - - Any additional user inputs + Any additional user inputs. Returns ------- @@ -243,32 +231,14 @@ def calc_turb_section_len(self, turbine_spacing_rotor_diameters, rotor_diameter_ class ArraySystem(CostModule): """ - - - \nThis module: - - * Calculates cable length to substation - - * Calculates number of strings in a subarray - - * Calculated number of strings - - * Calculates total cable length for each cable type - - * Calculates total trench length - - * Calculates total collection system cost based on amount of material, amount of labor, price data, cable length, and trench length. - - - - **Keys in the input dictionary are the following:** - - * Given below are attributes that define each cable type: - * conductor_size - (int) cross-sectional diameter of cable [in mm] - - - + Performs the following calculations: + + * Calculates cable length to substation + * Calculates number of strings in a subarray + * Calculated number of strings + * Calculates total cable length for each cable type + * Calculates total trench length + * Calculates total collection system cost based on amount of material, amount of labor, price data, cable length, and trench length. """ def __init__(self, input_dict, output_dict, project_name): @@ -286,8 +256,7 @@ def __init__(self, input_dict, output_dict, project_name): def calc_num_strings(self): """ - Calculate number of full and partial strings to support full plant - capacity. + Calculate number of full and partial strings to support full plant capacity. Parameters ---------- @@ -300,18 +269,18 @@ def calc_num_strings(self): Returns ------- - self.output_dict['total_turb_per_string'] : float + total_turb_per_string : float Number of turbines on each string - self.output_dict['num_full_strings'] : float + num_full_strings : float Number of complete strings in array turb_per_partial_string : float Number of turbines in the partial string (if applicable) - self.output_dict['num_partial_strings'] : float + num_partial_strings : float Number of partial strings (if applicable, 0 or 1) perc_full_string : list Percentage of maximum number of turbines per cable type on partial string - self.output_dict['num_turb_per_cable'] : list + num_turb_per_cable : list Number of turbines on each cable type in string """ @@ -366,9 +335,9 @@ def calc_num_turb_partial_strings(self, num_leftover_turb, num_turb_per_cable): Parameters ---------- - self.output_dict['num_leftover_turb'] : float + num_leftover_turb : float Number of turbines in partial string - self.output_dict['num_turb_per_cable'] : list + num_turb_per_cable : list List of number of turbines per cable type on a full string Returns @@ -495,14 +464,14 @@ def calc_total_cable_length( Instance of individual cable type cable_specs : dict Dictionary containing cable specifications - self.output_dict['num_full_strings'] : float + num_full_strings : float Number of complete strings in array - self.output_dict['num_partial_strings'] : float + num_partial_strings : float Number of partial strings (if applicable, 0 or 1) len_to_substation : int or float Total length of largest array cable required to connect each string to substation, km - self.output_dict['perc_partial_string'] : list + perc_partial_string : list List of percent of turbines per cable type on partial string relative to full string @@ -716,20 +685,14 @@ def estimate_construction_time(self, construction_time_input_data, construction_ Parameters ------- - duration_construction - - pd.DataFrame - rsmeans - - pd.DataFrame - trench_length_km - - + duration_construction : float + rsmeans : pd.DataFrame + trench_length_km : pd.DataFrame + turbine_rating_MW : float Returns ------- - - (pd.DataFrame) operation_data + operation_data : pd.DataFrame """ @@ -996,7 +959,7 @@ def outputs_for_detailed_tab(self, input_dict, output_dict): Returns ------- - list(dict) + list[dict] A list of dicts, with each dict representing a row of the data. """ result = [] diff --git a/landbosse/model/DevelopmentCost.py b/landbosse/model/DevelopmentCost.py index 9eede9f4..4a5d73b8 100644 --- a/landbosse/model/DevelopmentCost.py +++ b/landbosse/model/DevelopmentCost.py @@ -5,12 +5,8 @@ class DevelopmentCost(CostModule): """ - **DevelopmentCost.py - - -Created by Parangat Bhaskar on June 30, 2019 - - Creating a simple DevelopmentCost module for now. This module reads in a user input from the detailed input Excel - file and outputs this in the detailed output excel file. + Reads in a user input from the detailed input Excel file, and passes it through to + the detailed output Excel file. """ @@ -31,7 +27,7 @@ def calculate_costs(self): cost is retrieved from the project data. Returns - ------------------------------------ + ------- total_development_cost : pd.DataFrame data frame with total development cost by type of cost (e.g., Labor) """ @@ -56,11 +52,11 @@ def outputs_for_detailed_tab(self): 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() + Must be called after :py:meth:`run_module`. Returns ------- - list(dict) + list[dict] A list of dicts, with each dict representing a row of the data. """ @@ -86,7 +82,6 @@ def outputs_for_detailed_tab(self): def run_module(self): """ Runs the DevelopmentCost module and populates the IO dictionaries with calculated values. - """ try: diff --git a/landbosse/model/ErectionCost.py b/landbosse/model/ErectionCost.py index 7e369dc1..74368478 100644 --- a/landbosse/model/ErectionCost.py +++ b/landbosse/model/ErectionCost.py @@ -15,16 +15,16 @@ class Point(object): def __init__(self, x, y): - if type(x) == type(pd.Series(dtype=np.float64)): + if isinstance(x, pd.Series): self.x = float(x.values[0]) self.y = float(y.values[0]) - elif type(x) == type(np.array([])): + elif isinstance(x, np.ndarray): self.x = float(x[0]) self.y = float(y[0]) - elif type(x) == type(int(0)): + elif isinstance(x, int): self.x = float(x) self.y = float(y) - elif type(x) == type(float(0.0)): + elif isinstance(x, float): self.x = x self.y = y else: @@ -53,112 +53,49 @@ def point_in_polygon(pt, poly): class ErectionCost(CostModule): """ - ErectionCost.py - Created by Annika Eberle and Owen Roberts on Mar. 16, 2018 - Created by Alicia Key and Parangat Bhaskar on 01 June 2019 + Calculates the costs for erecting the tower and rotor nacelle assembly for land-based wind projects + (items in brackets are not yet implemented) using the following steps: - Calculates the costs for erecting the tower and rotor nacelle assembly for land-based wind projects - (items in brackets are not yet implemented) + * [Get terrain complexity] + * [Get site complexity] + * Get number of turbines + * Get duration of construction + * Get rate of deliveries + * Get daily hours of operation + * Get turbine rating + * Get component specifications + * [Get crane availability] - [Get terrain complexity] - [Get site complexity] - Get number of turbines - Get duration of construction - Get rate of deliveries - Get daily hours of operation - Get turbine rating - Get component specifications - [Get crane availability] + Price data is determined by: - Get price data - Get labor mobilization_prices by crew type - Get labor prices by crew type - Get equipment mobilization prices by equipment type - Get fuel prices - Get equipment prices by equipment type + * Getting labor mobilization_prices by crew type + * Getting labor prices by crew type + * Getting equipment mobilization prices by equipment type + * Getting fuel prices + * Getting equipment prices by equipment type - Calculate operational time for lifting components + Calculate operational time for lifting components - Estimate potential time delays due to weather + Estimate potential time delays due to weather - Calculate required labor and equip for erection (see equip_labor_by_type method below) - Calculate number of workers by crew type - Calculate man hours by crew type - Calculate number of equipment by equip type - Calculate equipment hours by equip type + Calculate required labor and equip for erection (see equip_labor_by_type method below): - Calculate erection costs by type (see methods below) - Calculate mobilization costs as function of number of workers by crew type, number of equipment by equipment type, labor_mobilization_prices, and equip_mobilization_prices - Calculate labor costs as function of man_hours and labor prices by crew type - Calculate fuel costs as function of equipment hours by equipment type and fuel prices by equipment type - Calculate equipment costs as function of equipment hours by equipment type and equipment prices by equipment type + * Calculate number of workers by crew type + * Calculate man hours by crew type + * Calculate number of equipment by equip type + * Calculate equipment hours by equip type - Sum erection costs over all types to get total costs + Calculate erection costs by type (see methods below): - Find the least cost option + * Calculate mobilization costs as function of number of workers by crew type, number of equipment by equipment type, labor_mobilization_prices, and equip_mobilization_prices + * Calculate labor costs as function of man_hours and labor prices by crew type + * Calculate fuel costs as function of equipment hours by equipment type and fuel prices by equipment type + * Calculate equipment costs as function of equipment hours by equipment type and equipment prices by equipment type + * Sum erection costs over all types to get total costs + * Find the least cost option - Return total erection costs - - Keys in the input dictionary are the following: - - construct_duration - (int) duration of construction (in months) - - rate_of_deliveries - (int) rate of deliveries (number of turbines per week) - - weather_window - (pd.DataFrame) window of weather data for project of interest. - - wind_shear_exponent - - (float) The exponent of the power law wind shear calculation - - overtime_multiplier: - (float) multiplier for overtime work (working 60 hr/wk vs 40 hr/wk) - - allow_same_flag - (bool) boolean flag to indicate whether choosing same base and - topping crane is allowed. - - operational_construction_time - (int) Number of hours per day when construction can happen. - - time_construct - (int) 'normal' (10 hours per day) or 'long' (24 hours per day) - - project_data - (dict) dictionary of pd.DataFrame for each of the csv files loaded - for the project. - - In turn, the project_data dictionary contains key value pairs of the - following: - - crane_specs: - (pd.DateFrame) Specs about the cranes for the cost calculations. - - equip - (pd.DataFrame) Equipment needed for various tasks - - crew - (pd.DataFrame) Crew configurations needed for various tasks - - components - (pd.DataFrame) components to build a wind turbine - - project - (pd.DataFrame) The project of the project to calculate. - - equip_price - (pd.DatFrame) Prices to operate various pieces of equipment. - - crew_price - (pd.DataFrame) THe prices for various crews - - material_price - (pd.DatFrame) Prices for various materials used during erection. - - rsmeans - (p.DataFrame) RSMeans data + Created by Annika Eberle and Owen Roberts on Mar. 16, 2018 and modified by Alicia Key and + Parangat Bhaskar on 01 June 2019 """ def __init__(self, input_dict, output_dict, project_name): @@ -166,12 +103,51 @@ 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 - + The input dictionary with key value pairs: + + construct_duration + (int) duration of construction (in months) + rate_of_deliveries + (int) rate of deliveries (number of turbines per week) + weather_window + (pd.DataFrame) window of weather data for project of interest. + wind_shear_exponent + (float) The exponent of the power law wind shear calculation + overtime_multiplier: + (float) multiplier for overtime work (working 60 hr/wk vs 40 hr/wk) + allow_same_flag + (bool) boolean flag to indicate whether choosing same base and + topping crane is allowed. + operational_construction_time + (int) Number of hours per day when construction can happen. + time_construct + (int) 'normal' (10 hours per day) or 'long' (24 hours per day) + project_data + (dict) dictionary of pd.DataFrame for each of the csv files loaded + for the project. The project_data dictionary contains key value pairs + of the following: + + crane_specs: + (pd.DateFrame) Specs about the cranes for the cost calculations. + equip + (pd.DataFrame) Equipment needed for various tasks + crew + (pd.DataFrame) Crew configurations needed for various tasks + components + (pd.DataFrame) components to build a wind turbine + project + (pd.DataFrame) The project of the project to calculate. + equip_price + (pd.DatFrame) Prices to operate various pieces of equipment. + crew_price + (pd.DataFrame) THe prices for various crews + material_price + (pd.DatFrame) Prices for various materials used during erection. + rsmeans + (p.DataFrame) RSMeans data output_dict : dict The output dictionary with key value pairs as found on the - output documentation. + output documentation. """ self.input_dict = input_dict self.output_dict = output_dict @@ -210,11 +186,11 @@ def outputs_for_detailed_tab(self): 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() + Must be called after :py:meth:`run_module`. Returns ------- - list(dict) + result : list[dict] A list of dicts, with each dict representing a row of the data. """ result = [] @@ -423,26 +399,15 @@ def calculate_erection_operation_time(self): """ Calculates operation time required for each type of equipment included in project data. - self.output_dict['possible_cranes'] = possible_cranes - self.output_dict['erection_operation_time'] = erection_operation_time_dict - - self.input_dict keys - --------------------- - construct_duration : int - int duration of construction (in months) - - operational_construction_time : int - Number of hours each day that are available for construction hours. - - self.output_dict keys - --------------------- - self.output_dict['possible_cranes'] : possible_cranes (with geometry) - self.output_dict['erection_operation_time'] : Operation time for each crane. + Uses the ``construction_duration`` and ``operational_construction_time`` from the ``input_dict`` + to determine which cranes to use to meet construction needs. Returns ------- - pd.DataFrame, pd.DataFrame - Dataframe of possible_cranes (with geometry) and operational time for cranes + possible_cranes : pd.DataFrame + Dataframe of possible_cranes with geometry + operation_time : pd.DataFrame + Operational time by crane """ project_data = self.input_dict["project_data"] construct_duration = self.input_dict["construct_duration"] # Total project construction time (months) @@ -588,22 +553,19 @@ def calculate_offload_operation_time(self): """ Calculates time for the offload operation. - self.input_dict keys - -------------------- - project_data : dict - dict of data frames for each of the csv files loaded for the project - - operational_construction_time : int - operational hours of construction - - rate_of_deliveries : int - rate of deliveries of turbines ready for erection. - - self.output_dict key - -------------------- - possible_cranes : pd.DataFrame - Dataframe of cranes possibly available for the operation + Uses the following from ``input_dict``: + project_data : dict + dict of data frames for each of the csv files loaded for the project + operational_construction_time : int + operational hours of construction + rate_of_deliveries : int + rate of deliveries of turbines ready for erection. + Returns + ------- + tuple[pd.DataFrame, pd.DataFrame] + Dataframe of cranes possibly available for the operation, and the number of hours + per day where construction can occur. operation_time : int Integer of number of hours per day construction can proceed. """ @@ -721,7 +683,7 @@ def calculate_crane_lift_polygons(self, crane_grouped): Returns ------- - pd.DataFrame + crane_poly : pd.DataFrame A dataframe of the cranes and their lifting polygons. """ crane_poly = pd.concat(self.iterate_crane_lift_polygons(crane_grouped)) @@ -792,11 +754,12 @@ def calculate_component_lift_max_wind_speed(self, *, component_group, crane_poly For the maximum wind speed calculations, we use these equations to calculation vmax, which is the maximum permissible wind speed: - vmax = max_TAB * sqrt(1.2 * mh / aw), where - mh = hoist load - aw = area exposed to wind = surface area * coeff drag - 1.2 = constant in m^2 / t - vmax_tab = maximum load speed per load chart + :math:`vmax = max_{TAB} * \sqrt{1.2 * mh / aw}`, where\n + :math:`mh` = hoist load\n + :math:`aw` = area exposed to wind = surface area * coeff drag\n + 1.2 = constant in :math:`m^2 / t`\n + :math:`vmax_{tab}` = maximum load speed per load chart\n + (source: pg. 33 of Liebherr) See the source code for this method on how this calculation is used. @@ -825,7 +788,7 @@ def calculate_component_lift_max_wind_speed(self, *, component_group, crane_poly Returns ------- - dict + result : dict Returns a dict of pd.DataFrame values. The key "component_max_speed" is the the dataframe of max component speeds. The key "crane_poly" is a COPY of the crane_poly dataframe passed as a parameter to this function and with a column @@ -953,10 +916,12 @@ def aggregate_erection_costs(self): Returns ------- - Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame] - Two dataframes: First, utilizing the separate cranes for base and topping. - Second, utilizing same crane for base and topping, - Third is crew cost. + separate_topbase_crane_cost : pd.DataFrame + Crane costs for using separate cranes for base and topping. + topbase_same_crane_cost : pd.DataFrame + Crane costs for using the same crane for base and topping. + crew_cost : pd.DataFrame + Crew costs. """ join_wind_operation = self.output_dict["join_wind_operation"] overtime_multiplier = self.input_dict["overtime_multiplier"] @@ -1160,17 +1125,15 @@ def find_minimum_cost_cranes(self): Finds the minimum cost crane(s) based on the aggregated labor, equipment, mobilization and fuel costs for erection. - self.output_dict keys used as inputs - ------------------------------------ - separate_basetop : pd.DataFrame - data frame with aggregated labor, equipment, mobilization, and fuel costs for utilizing - separate cranes for base and topping. - same_basetop : pd.DataFrame - data frame with aggregated labor, equipment, mobilization, and fuel costs for utilizing the - same crane for base and topping - - allow_same_flag : boolean - flag to indicate whether choosing same base and topping crane is allowed + The following the ``output_dict`` are used as inputs: + separate_basetop : pd.DataFrame + data frame with aggregated labor, equipment, mobilization, and fuel costs for utilizing + separate cranes for base and topping. + same_basetop : pd.DataFrame + data frame with aggregated labor, equipment, mobilization, and fuel costs for utilizing the + same crane for base and topping + allow_same_flag : boolean + flag to indicate whether choosing same base and topping crane is allowed """ allow_same_flag = self.input_dict["allow_same_flag"] separate_basetop = self.output_dict["separate_basetop"] @@ -1229,10 +1192,12 @@ def calculate_management_crews_cost(self, erection_cost): Returns ------- - pd.DataFrame, pd.DataFrame, float - The first dataframe are management costs by each role on each team. - The second dataframe are management costs summed over aggregations of - teams. The float is the sum of all the management costs for erection. + management_crews : pd.DataFrame + Costs by each role and team + management_crew_cost_grouped : pd.DataFrame + Costs totals by groups of teams. + total_management_cost : float + Sum of all the management costs for erection. """ num_turbines = self.input_dict["num_turbines"] diff --git a/landbosse/model/FoundationCost.py b/landbosse/model/FoundationCost.py index f1bbfe5e..bab37e92 100644 --- a/landbosse/model/FoundationCost.py +++ b/landbosse/model/FoundationCost.py @@ -11,18 +11,17 @@ class FoundationCost(CostModule): """ - **FoundationCost.py** + Calculates the costs of constructing foundations for land-based wind projects + *(items in brackets are not yet implemented)*: + + * Created by Annika Eberle and Owen Roberts on Apr. 3, 2018 + * Refactored by Parangat Bhaskar and Alicia Key on June 3, 2019 - - Created by Annika Eberle and Owen Roberts on Apr. 3, 2018 - - - Refactored by Parangat Bhaskar and Alicia Key on June 3, 2019 - - \nCalculates the costs of constructing foundations for land-based wind projects *(items in brackets are not yet implemented)*: * Get number of turbines * Get duration of construction - * Get daily hours of operation* # todo: add to process diagram - * Get season of construction* # todo: add to process diagram + * Get daily hours of operatio + * Get season of construction * [Get region] * Get rotor diameter * Get hub height @@ -39,141 +38,20 @@ class FoundationCost(CostModule): * [Use region to determine weather data] - \n\nGiven below is the set of calculations carried out in this module: + Given below is the set of calculations carried out in this module: * Calculate the foundation loads using the rotor diameter, hub height, and turbine rating - * Determine the foundation size based on the foundation loads, buoyant foundation design flag, and type of tower technology - * Estimate the amount of material needed for foundation construction based on foundation size and number of turbines - * Estimate the amount of time required to construct foundation based on foundation size, hours of operation, duration of construction, and number of turbines - * Estimate the additional amount of time for weather delays (currently only assessing wind delays) based on hourly weather data, construction time, hours of operation, and season of construction - * Estimate the amount of labor required for foundation construction based on foundation size, construction time, and weather delay - * Calculate number of workers by crew type - * Calculate man hours by crew type - + * Calculate number of workers by crew type + * Calculate man hours by crew type * Estimate the amount of equipment needed for foundation construction based on foundation size, construction time, and weather delay - * Calculate number of equipment by equip type - * Calculate equipment hours by equip type - - - Calculate the total foundation cost based on amount of equipment, amount of labor, amount of material, and price data. - - - **Keys in the input dictionary are the following:** - - depth - (int) depth of foundation [in m] - - - component_data - (pd.DataFrame) data frame with wind turbine component data - - def __init__(self, input_dict, output_dict, project_name): - self.input_dict = input_dict - self.output_dict = output_dict - self.project_name = project_name - - - num_turbines - (int) total number of turbines in wind farm - - duration_construction - (int) estimated construction time in months - - num_delays - (int) Number of delay events - - avg_hours_per_delay - (float) Average hours per delay event - - std_dev_hours_per_delay - (float) Standard deviation from average hours per delay event - - delay_speed_m_per_s - (float) wind speed above which weather delays kick in - - start_delay_hours - (int) - - mission_time_hours - (int) - - gust_wind_speed_m_per_s - (float) - - wind_height_of_interest_m - (int) - - wind_shear_exponent - (float) - - season_construct - list of seasons (like ['spring', 'summer']) for the construction. - - time_construct - list of time windows for constructions. Use ['normal'] for a - 0800 to 1800 schedule 10 hour schedule. Use ['long'] for an - overnight 1800 to 2359, 0000 to 0759 overnight schedule. Use - ['normal', 'long'] for a 24-hour schedule. - - operational_hrs_per_day - (float) - - - material_price - (pd.DataFrame) dataframe containing foundation cost related material prices - - rsmeans - (pd.DataFrame) TODO: Formal definition for rsmeans? - - - **Keys in the output dictionary are the following:** - - F_dead_kN_per_turbine - (float) foundation dead load [in kN] - - F_horiz_kN_per_turbine - (float) total lateral load [kN] - - M_tot_kN_m_per_turbine - (float) Moment [kN.m] - - Radius_o_m - (float) foundation radius based on overturning moment [in m] - - Radius_g_m - (float) foundation radius based on gapping [in m] - - Radius_b_m - (float) foundation radius based on bearing pressure [in m] - - Radius_m - (float) largest foundation radius based on all three foundation design criteria: moment, gapping, bearing [in m] - - foundation_volume_concrete_m3_per_turbine - (float) volume of a round, raft foundation [in m^3] - - steel_mass_short_ton - (float) short tons of reinforcing steel - - material_needs_per_turbine - (pd.DataFrame) table containing material needs info for -> Steel - rebar, Concrete 5000 psi, Excavated dirt, Backfill. - - operation_data - (pd.DataFrame) TODO: What's the best one line definition for this? - - - **TODO: Weather delay set of outputs -> ask Alicia for formal definitions of these keys.** - - total_foundation_cost - (pd.DataFrame) summary of foundation costs (in USD) broken down into 4 main categories: - 1. Equipment Rental - 2. Labor - 3. Materials - 4. Mobilization + * Calculate number of equipment by equip type + * Calculate equipment hours by equip type + * Calculate the total foundation cost based on amount of equipment, amount of labor, amount of material, and price data. """ def __init__(self, input_dict, output_dict, project_name): @@ -181,12 +59,83 @@ 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 + The input dictionary with key value pairs: + + depth : int + depth of foundation [in m] + component_data : pd.DataFrame + data frame with wind turbine component data + + num_turbines : int + total number of turbines in wind farm + duration_construction : int + estimated construction time in months + num_delays : int + Number of delay events + avg_hours_per_delay : float + Average hours per delay event + std_dev_hours_per_delay : float + Standard deviation from average hours per delay event + delay_speed_m_per_s : float + wind speed above which weather delays kick in + start_delay_hours : int + TODO + mission_time_hours : int + TODO + gust_wind_speed_m_per_s : float + TODO + wind_height_of_interest_m : int + TODO + wind_shear_exponent : float + TODO + season_construct : list[str] + list of seasons (like ['spring', 'summer']) for the construction. + time_construct : list[int] + list of time windows for constructions. Use ['normal'] for a + 0800 to 1800 schedule 10 hour schedule. Use ['long'] for an + overnight 1800 to 2359, 0000 to 0759 overnight schedule. Use + ['normal', 'long'] for a 24-hour schedule. + operational_hrs_per_day : float + TODO + material_price : pd.DataFrame + dataframe containing foundation cost related material prices + rsmeans : pd.DataFrame + TODO: Formal definition for rsmeans? output_dict : dict - The output dictionary with key value pairs as found on the - output documentation. + The output dictionary with key value pairs: + + F_dead_kN_per_turbine : float + foundation dead load [in kN] + F_horiz_kN_per_turbine : float + total lateral load [kN] + M_tot_kN_m_per_turbine : float + Moment [kN.m] + Radius_o_m : float + foundation radius based on overturning moment [in m] + Radius_g_m : float + foundation radius based on gapping [in m] + Radius_b_m : float + foundation radius based on bearing pressure [in m] + Radius_m : float + largest foundation radius based on all three foundation design criteria: moment, gapping, bearing [in m] + foundation_volume_concrete_m3_per_turbine : float + volume of a round, raft foundation [in m^3] + steel_mass_short_ton : float + short tons of reinforcing steel + material_needs_per_turbine : pd.DataFrame + table containing material needs info for -> Steel - rebar, Concrete 5000 psi, Excavated dirt, Backfill. + operation_data : pd.DataFrame + operational data + total_foundation_cost : pd.DataFrame + summary of foundation costs (in USD) broken down into 4 main categories: + + * Equipment Rental + * Labor + * Materials + * Mobilization + + **TODO: Weather delay set of outputs -> ask Alicia for formal definitions of these keys.** """ self.input_dict = input_dict @@ -202,44 +151,33 @@ class documentation def calculate_foundation_load(self, foundation_load_input_data, foundation_load_output_data): """ + Calculates the foundation load. - Function to calculate foundation load. - - Parameters - ------- - Int Section height m - - Surface area sq (in m^2) + Uses the following keys from the ``foundation_load_input_data``: - Coeff drag (installed) - - Lever arm m (in m) - - Multplier drag rotor - - Multiplier tower drag - - Mass tonne + * Section height m + * Surface area sq m + * Coeff drag (installed) + * Lever arm m m + * Multplier drag rotor + * Multiplier tower drag + * Mass tonne Returns ------- - Dead load [in N] -> F_dead_kN_per_turbine - - Lateral load [in N] -> F_horiz_kN_per_turbine - - Moment [N.m] -> M_tot_kN_m_per_turbine - - Foundation radius based on overturning moment [in m] -> Radius_o_m - - Foundation radius based on slipping [in m] -> Radius_s_m - - Foundation radius based on gapping [in m] -> Radius_g_m - - Foundation radius based on bearing pressure [in m] -> Radius_b_m - - Largest foundation radius based on all three foundation design criteria (moment, gapping, bearing [in m]) -> Radius_m + foundation_load_output_data : dict + Dictionary containing the following: + + * Dead load [in N] -> F_dead_kN_per_turbine + * Lateral load [in N] -> F_horiz_kN_per_turbine + * Moment [N.m] -> M_tot_kN_m_per_turbine + * Foundation radius based on overturning moment [in m] -> Radius_o_m + * Foundation radius based on slipping [in m] -> Radius_s_m + * Foundation radius based on gapping [in m] -> Radius_g_m + * Foundation radius based on bearing pressure [in m] -> Radius_b_m + * Largest foundation radius based on all three foundation design criteria (moment, gapping, bearing [in m]) -> Radius_m Raises ------ @@ -420,18 +358,16 @@ def r_b(x): def determine_foundation_size(self, foundation_size_input_data, foundation_size_output_data): """ - Function to calculate the volume of a round, raft foundation. Assumes foundation made of concrete with 1 m thickness. + Calculates the volume of a round, raft foundation. Assumes foundation made of concrete with 1 m thickness. - Parameters - ------- Largest foundation radius based on all three foundation design criteria: moment, gapping, bearing [in m] -> Radius_m [in m] - depth of foundation [in m] -> depth - Returns ------- - Foundation volume [in m^3] -> foundation_volume_concrete_m3_per_turbine + foundation_size_output_data : dict + Dictionary gets the additional ``foundation_volume_concrete_m3_per_turbine`` field + consisting of the foundation volume [in m^3]. """ # TODO: still updating/fine-tuning foundation size equations for small DW (Parangat - Feb 27, 2020) @@ -463,14 +399,14 @@ def estimate_material_needs_per_turbine( Parameters - ------- - Foundation concrete volume [in m^3] -> foundation_volume_concrete_m3_per_turbine - + ---------- + material_needs_per_turbine_input_data : dict + Relies on the foundation concrete volume [in m^3] (``foundation_volume_concrete_m3_per_turbine``). Returns ------- - - (Returns pd.DataFrame) material_needs_per_turbine + material_needs_per_turbine_output_data : pd.DataFrame + Adds the ``material_needs_per_turbine`` key, value pair. """ @@ -514,21 +450,17 @@ def estimate_construction_time(self, construction_time_input_data, construction_ Function to estimate construction time on per turbine basis. TODO: What's a better definition of this function. It's task is to return a pd.DataFrame (operation_data). Parameters - ------- - duration_construction - - pd.DataFrame - rsmeans - - pd.DataFrame - material_needs_per_turbine - + ---------- + construction_time_time_input_data : dict + Dictionary containing the following: + * construct_duration : float + * rsmeans : pd.DataFrame + * material_needs_per_turbine : pd.DataFrame Returns ------- - - (pd.DataFrame) operation_data + operation_data : pd.DataFrame """ @@ -608,21 +540,15 @@ def calculate_weather_delay(self, weather_delay_input_data, weather_delay_output """ Function to calculate wind delay for foundations. - Keys in weather_delay_input_data - -------------------------------- - weather_window - - duration_construction - - start_delay - - critical_wind_speed - - operational_hrs_per_day - - height_interest - - wind_shear_exponent + Keys in ``weather_delay_input_data``: + + * weather_window + * duration_construction + * start_delay + * critical_wind_speed + * operational_hrs_per_day + * height_interest + * wind_shear_exponent """ # construct WeatherDelay module @@ -641,33 +567,19 @@ def calculate_costs(self, calculate_costs_input_dict, calculate_costs_output_dic """ Function to calculate the total foundation cost. - Keys in input dictionary - ------------------------ - pd.DataFrame - material_needs_per_turbine - - pd.DataFrame - material_price - - pd.DataFrame - operation_data - - wind_delay_time - - operational_hrs_per_day - - wind_multiplier - - pd.DataFrame - rsmeans - + Keys in ``calculate_costs_input_dict`` dictionary: + + * material_needs_per_turbine (pd.DataFrame) + * material_price(pd.DataFrame) + * operation_data (pd.DataFrame) + * wind_delay_time + * operational_hrs_per_day + * wind_multiplier (pd.DataFrame) + * rsmeans Returns ------- - - (pd.DataFrame) total_foundation_cost - - + total_foundation_cost : pd.DataFrame """ material_vol_entire_farm = calculate_costs_output_dict["material_needs_entire_farm"] @@ -812,11 +724,11 @@ 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() + Must be called after :py:meth:`run_module`. Returns ------- - list(dict) + result : list[dict] A list of dicts, with each dict representing a row of the data. """ @@ -978,10 +890,6 @@ def run_module(self): """ Runs the FoundationCost module and populates the IO dictionaries with calculated values. - Parameters - ---------- - - Returns ------- tuple diff --git a/landbosse/model/GridConnectionCost.py b/landbosse/model/GridConnectionCost.py index 817f1f76..a081a2e4 100644 --- a/landbosse/model/GridConnectionCost.py +++ b/landbosse/model/GridConnectionCost.py @@ -8,27 +8,16 @@ class GridConnectionCost(CostModule): """ - TransDistCost.py - - Created by Annika Eberle and Owen Roberts on Dec. 17, 2018 - - Refactored by Parangat Bhaskar and Alicia Key on June 3, 2019 - - Calculates the costs associated with transmission and distribution for land-based wind projects (module is currently based on curve fit of empirical data) - + Calculates the costs associated with transmission and distribution for land-based wind projects + (module is currently based on curve fit of empirical data) + * Get distance to interconnection * Get interconnection voltage * Get toggle for new switchyard * Return total transmission and distribution costs - - \n\n**Keys in the input dictionary are the following:** - - distance_to_interconnect_mi - (float) distance to interconnection [in miles] - - \n\n**Keys in the output dictionary are the following:** - - trans_dist_usd - (float) total transmission and distribution costs [in USD] - + + - Created by Annika Eberle and Owen Roberts on Dec. 17, 2018 + - Refactored by Parangat Bhaskar and Alicia Key on June 3, 2019 """ def __init__(self, input_dict, output_dict , project_name): @@ -36,12 +25,16 @@ 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 + The input dictionary with key value pairs: + + distance_to_interconnect_mi + (float) distance to interconnection [in miles output_dict : dict - The output dictionary with key value pairs as found on the - output documentation. + The output dictionary with key value pairs: + + trans_dist_usd + (float) total transmission and distribution costs [in USD] """ self.input_dict = input_dict self.output_dict = output_dict @@ -51,10 +44,6 @@ def calculate_costs(self, calculate_costs_input_dict, calculate_costs_output_dic """ Function to calculate total costs for transmission and distribution. - Parameters - ---------- - - Returns ------- tuple @@ -107,11 +96,11 @@ 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() + Must be called after ``run_module`` Returns ------- - list(dict) + list[dict] A list of dicts, with each dict representing a row of the data. """ result = [] @@ -141,7 +130,7 @@ def outputs_for_module_type_operation(self, input_dict, output_dict): Returns ------- - list + list[dict] List of dicts, with each dict representing a row for the output. """ @@ -169,10 +158,6 @@ def run_module(self): """ Runs the TransDistCost module and populates the IO dictionaries with calculated values. - Parameters - ---------- - - Returns ------- tuple diff --git a/landbosse/model/ManagementCost.py b/landbosse/model/ManagementCost.py index 65b51425..0c2d282f 100644 --- a/landbosse/model/ManagementCost.py +++ b/landbosse/model/ManagementCost.py @@ -6,76 +6,6 @@ class ManagementCost: This class models management costs of a wind plant. Its inputs are configured with a dictionary with the key value pairs being the inputs into the model. - - See the input_output documentation below for a description of the key - names for this inputs values dictionary. - - The INPUT keys are the following: - - project_value_usd - (float) Sum of all other BOS costs (e.g., roads, foundations, erection) - - foundation_cost_usd - (float) Foundation costs for the project - - construct_duration - (float) Project duration (in months) - - num_hwy_permits - (int) Number of highway permits needed for the project - - markup_constants - (dict) Markup and contingency costs that can be set by user - (see the markup_contingency method for key names to use in this dictionary) - - num_turbines - (int) Number of turbines for project - - project_size_megawatts - (float) Total power output of project in megawatts - - hub_height_meters - (float) Hub height for all turbines in meters - - project_size_megawatts - - (float) Total power output of project in megawatts - - num_access_roads - (int) Number of access roads into project site - - site_facility_building_area_df - (pd.DataFrame) Building areas dataframe. This should be loaded - from a .csv file on the filesystem. - - The OUTPUT keys are the following - - insurance - (float) The cost of insurance for the project. USD. Eqn. 3.4.1 - - construction_permitting - (float) The cost of the construction permitting. USD. - - project_management - (float) The cost of the project management. USD. - - bonding - (float) The cost of binding for the project. USD. - - engineering_usd - (float) Site-specific engineering costs for foundations and collection. USD. - - site_security_usd - (float) estimate cost of site security. USD. - - site_facility - (float) Site facility costs. USD. - - markup_contingency - (float) Markup contingency costs. USD. - - total_cost - (float) Total cost of everything else """ def __init__(self, input_dict, output_dict, project_name): @@ -87,10 +17,54 @@ def __init__(self, input_dict, output_dict, project_name): Parameters ---------- input_dict : dict - Dictionary with the inputs key / value pairs + Dictionary with the inputs key / value pairs: + + project_value_usd + (float) Sum of all other BOS costs (e.g., roads, foundations, erection) + foundation_cost_usd + (float) Foundation costs for the project + construct_duration + (float) Project duration (in months) + num_hwy_permits + (int) Number of highway permits needed for the project + markup_constants + (dict) Markup and contingency costs that can be set by user + (see the markup_contingency method for key names to use in this dictionary) + num_turbines + (int) Number of turbines for project + project_size_megawatts + (float) Total power output of project in megawatts + hub_height_meters + (float) Hub height for all turbines in meters + project_size_megawatts + (float) Total power output of project in megawatts + num_access_roads + (int) Number of access roads into project site + site_facility_building_area_df + (pd.DataFrame) Building areas dataframe. This should be loaded + from a .csv file on the filesystem. output_dict : dict - Dictionary with output key / value pairs. + Dictionary with output key / value pairs: + + insurance + (float) The cost of insurance for the project. USD. Eqn. 3.4.1 + construction_permitting + (float) The cost of the construction permitting. USD. + project_management + (float) The cost of the project management. USD. + bonding + (float) The cost of binding for the project. USD. + engineering_usd + (float) Site-specific engineering costs for foundations and collection. USD. + site_security_usd + (float) estimate cost of site security. USD. + site_facility + (float) Site facility costs. USD. + markup_contingency + (float) Markup contingency costs. USD. + total_cost + (float) Total cost of everything else """ self.in_distributed_mode = 'override_total_management_cost' in input_dict self.validate_inputs(input_dict) @@ -145,16 +119,13 @@ def insurance(self): Eqn. 3.4.1 Includes: - - Builder's risk - - General liability - - Umbrella policy - - Professional liability - - It uses only the self.project_value attribute in calculations. + + * Builder's risk + * General liability + * Umbrella policy + * Professional liability + + It uses only the ``project_value`` attribute in calculations. :math:`C_I = 0.0056 * V_p` @@ -199,27 +170,17 @@ def project_management(self): Calculate project management costs based on project size; equation based on empirical data from industry. Includes: - Project manager and assistant project manager for site - - Site managers for civil, electrical, and erection - - QA/QC management - - QA/QC inspections for civil, structural, electrical, and mechanical - - Administrative support for the site - - Health and safety supervisors - - Environmental supervisors - - Office equipment & materials - - Site radios, communication, and vehicles - - Management team per diem and travel - - Legal and public relations + * Project manager and assistant project manager for site + * Site managers for civil, electrical, and erection + * QA/QC management + * QA/QC inspections for civil, structural, electrical, and mechanical + * Administrative support for the site + * Health and safety supervisors + * Environmental supervisors + * Office equipment & materials + * Site radios, communication, and vehicles + * Management team per diem and travel + * Legal and public relations Returns ------- @@ -239,15 +200,11 @@ def markup_contingency(self): """ Calculate mark-up and contingency costs based on project value. Includes: - Markup contingency - - Markup warranty management - - Sales and use tax - - Markup overhead - - Markup profit margin + * Markup contingency + * Markup warranty management + * Sales and use tax + * Markup overhead + * Markup profit margin Returns ------- @@ -311,53 +268,39 @@ def site_facility(self): Uses empirical data to estimate cost of site facilities and security, including - Site facilities: + * Site facilities: - Building design and construction + * Building design and construction + * Drilling and installing a water well, including piping + * Electric power for a water well + * Septic tank and drain field - Drilling and installing a water well, including piping + * Site security: - Electric power for a water well - - Septic tank and drain field - - - Site security: - - Constructing and reinstating the compound - - Constructing and reinstating the batch plant site - - Setting up and removing the site offices for the contractor, turbine supplier, and owner - - Restroom facilities - - Electrical and telephone hook-up - - Monthly office costs - - Signage for project information, safety and directions - - Cattle guards and gates - - Number of access roads + * Constructing and reinstating the compound + * Constructing and reinstating the batch plant site + * Setting up and removing the site offices for the contractor, turbine supplier, and owner + * Restroom facilities + * Electrical and telephone hook-up + * Monthly office costs + * Signage for project information, safety and directions + * Cattle guards and gates + * Number of access roads In main.py, a csv is loaded into a Pandas dataframe. The columns of the dataframe must be: - Size Min (MW) - Minimum power output for a plant that needs a certain size of - building. - - Size Max (MW) - Maximum power output of a plant that need a certain size of - building. - - Building Area (sq. ft.) - The area of the building needed to provide O & M support to plants - with power output between "Size Min (MW)" and "Size Max (MW)". + Size Min (MW) + Minimum power output for a plant that needs a certain size of + building. + Size Max (MW) + Maximum power output of a plant that need a certain size of + building. + Building Area (sq. ft.) + The area of the building needed to provide O & M support to plants + with power output between "Size Min (MW)" and "Size Max (MW)". Returns ------- @@ -418,7 +361,7 @@ def outputs_for_detailed_tab(self): 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() + Must be called after :py:meth:`run_module`. Returns ------- diff --git a/landbosse/model/Manager.py b/landbosse/model/Manager.py index c582a83d..d1188e08 100644 --- a/landbosse/model/Manager.py +++ b/landbosse/model/Manager.py @@ -25,12 +25,10 @@ def __init__(self, input_dict, output_dict): """ This initializer sets up the instance variables of: - self.cost_modules: A list of cost module instances. Each of the + * ``cost_modules``: A list of cost module instances. Each of the instances must implement the method input_output. - - self.input_dict: A placeholder for the inputs dictionary - - self.output_dict: A placeholder for the output dictionary + * ``input_dict``: A placeholder for the inputs dictionary + * ``output_dict``: A placeholder for the output dictionary """ self.input_dict = input_dict self.output_dict = output_dict diff --git a/landbosse/model/SitePreparationCost.py b/landbosse/model/SitePreparationCost.py index ba0025ec..94e1f923 100644 --- a/landbosse/model/SitePreparationCost.py +++ b/landbosse/model/SitePreparationCost.py @@ -8,126 +8,67 @@ class SitePreparationCost(CostModule): """ - **SitePreparationCost.py** - - - Created by Annika Eberle and Owen Roberts on Apr. 3, 2018 - - - Refactored by Parangat Bhaskar and Alicia Key on Jun 3, 2019 - - - - **Calculates cost of constructing roads for land-based wind projects:** + Calculates cost of constructing roads for land-based wind projects: - Get terrain complexity - - Get turbine spacing - - Get road width - - Get number of turbines - - Get turbine rating - - Get duration of construction* #todo: add to process diagram - - Get road length - - Get weather data - - Get road thickness - - Calculate volume of road based on road thickness, road width, and road length - - Calculate road labor and equipment costs by operation and type using RSMeans data - - Calculate man hours and equipment hours for compaction of soil based on road length, road thickness, soil type, road width, and equipment size - - Calculate man hours and equipment hours for mass material movement based on land cover, terrain complexity, and road length - - Calculate man hours and equipment hours for rock placement based on equipment size, distance to quarry, and volume of road - - Calculate man hours and equipment hours for compaction of rock based on road length, road thickness, and rock type - - Calculate man hours and equipment hours for final grading based on road length - - Calculate quantity of materials based on volume of materials - - Calculate material costs by type - - Calculate material costs using quantity of materials by material type and material prices by material type - - Sum road costs over all operations and material types to get total costs by type of cost (e.g., material vs. equipment) - - Return total road costs by type of cost - - **Keys in the input dictionary are the following:** - - - road_length - - - road_width - - - road_thickness - - - crane_width - - - num_access_roads #TODO: Add to excel inputs sheet - - - num_turbines - - - rsmeans (dataframe) - - - duration_construction - - - wind_delays - - - wind_delay_time - - - material_price (dataframe) - - - rsmeans_per_diem - - - rotor_diameter_m - - - turbine_spacing_rotor_diameters - - - **Keys in the output dictionary are the following:** - - - road_length_m - - - road_volume_m3 - - - depth_to_subgrade_m - - - crane_path_widthm - - - road_thickess_m - - - road_width_m - - - road_width_m - - - material_volume_cubic_yards - - - road_construction_time - - - topsoil_volume - - - embankment_volume_crane - - - embankment_volume_road - - - rough_grading_area - - - material_needs (dataframe) - - - operation_data (dataframe) - - - total_road_cost - - - + Keys in the input dictionary are the following: + + - ``road_length`` + - ``road_width`` + - ``road_thickness`` + - ``crane_width`` + - ``num_access_roads`` + - ``num_turbines`` + - ``rsmeans`` (dataframe) + - ``duration_construction`` + - ``wind_delays`` + - ``wind_delay_time`` + - ``material_price`` + - ``rsmeans_per_diem`` + - ``rotor_diameter_m`` + - ``turbine_spacing_rotor_diameters`` + + Keys in the output dictionary are the following: + + - ``road_length_m`` + - ``road_volume_m3`` + - ``depth_to_subgrade_m`` + - ``crane_path_widthm`` + - ``road_thickess_m`` + - ``road_width_m`` + - ``road_width_m`` + - ``material_volume_cubic_yards`` + - ``road_construction_time`` + - ``topsoil_volume`` + - ``embankment_volume_crane`` + - ``embankment_volume_road`` + - ``rough_grading_area`` + - ``material_needs`` + - ``operation_data`` + - ``total_road_cost`` + + Created by Annika Eberle and Owen Roberts on Apr. 3, 2018 and refactored by Parangat Bhaskar and Alicia Key on Jun 3, 2019 """ def __init__(self, input_dict, output_dict, project_name): @@ -174,40 +115,27 @@ def calculate_road_properties(self, road_properties_input, road_properties_outpu Parameters ---------- - - int num_turbines + num_turbines : int number of turbines in wind farm - - unitless turbine_spacing_rotor_diameters + turbine_spacing_rotor_diameters : float Immediate spacing between two turbines as a function of rotor diameter - - int rotor_diameter_m + rotor_diameter_m : int Rotor diameter - - float crane_width + crane_width : float Crane width in meters - - float road_thickness + road_thickness : float Road thickness in inches - - float road_width_ft + road_width_ft : float Road width in feet - - Returns ---------- - - road_length_m + road_length_m : float Calculated road length (in m) - - road_volume_m3 + road_volume_m3 : float Calculated road volume (in m^3) - - material_volume_cubic_yards + material_volume_cubic_yards : float Material volume required (in cubic yards) based on road volume - - """ if road_properties_input["road_distributed_wind"] == True or road_properties_input["turbine_rating_MW"] < 0.1: @@ -254,33 +182,24 @@ def estimate_construction_time(self, estimate_construction_time_input, estimate_ Parameters ---------- - float crane_path_width_m + crane_path_width_m : float Width of crane path (in m) - - float road_length_m + road_length_m : float Road length (in m) - - float depth_to_subgrade_m + depth_to_subgrade_m : float Depth to subgarde (in m) - - float road_volume + road_volume : float Road volume (in m^3) - - float road_thickness_m + road_thickness_m : float Road thickness (in m) - - Returns ---------- - - pd.DataFrame operation_data + operation_data : pd.DataFrame Dataframe which conatains following outputs: - - Number of days required for construction - + - Number of days required for construction - Number of crews required to complete roads construction in specified construction time - - Cost of labor and equipment rental prior to weather delays """ @@ -481,27 +400,24 @@ def calculate_costs(self, calculate_cost_input_dict, calculate_cost_output_dict) Parameters ---------- - pd.Dataframe RSMeans - Dataframe containing labor and equipment rental costs - - pd.DataFrame operation_data - DataFrame containing estimates for total roads construction time and cost + calculate_cost_input_dict: dict + Dictionary with the following: + + rsmeans : pd.Dataframe + Dataframe containing labor and equipment rental costs + operation_data : pd.DataFrame + DataFrame containing estimates for total roads construction time and cost Returns ---------- - - pd.DataFrame total_road_cost + total_road_cost : pd.DataFrame Dataframe containing following calculated outputs (after weather delay considerations): - Total labor cost - - - Totoal material cost - + - Total material cost - Total equipment rental cost - - Total mobilization cost - - Any other related costs @@ -760,10 +676,9 @@ 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. - Returns ------- - list(dict) + list[dict] A list of dicts, with each dict representing a row of the data. """ result = [] @@ -929,8 +844,7 @@ def outputs_for_module_type_operation(self, input_dict, output_dict): def run_module(self): """ - Runs the SitePreparation module and populates the IO dictionaries with calculated values. - + Runs the module and populates the IO dictionaries with calculated values. """ try: self.calculate_road_properties(self.input_dict, self.output_dict) diff --git a/landbosse/model/SubstationCost.py b/landbosse/model/SubstationCost.py index 4751aee6..dcb9d1e5 100644 --- a/landbosse/model/SubstationCost.py +++ b/landbosse/model/SubstationCost.py @@ -7,33 +7,26 @@ class SubstationCost(CostModule): """ - **SubstationCost.py** - - - Created by Annika Eberle and Owen Roberts on Dec. 17, 2018 - - - Refactored by Parangat Bhaskar and Alicia Key on June 3, 2019 - Calculates the costs associated with substations for land-based wind projects *(module is currently based on curve fit of empirical data)* + Calculation consists of the following steps: + + * Get project size: ``project_size_megawatts = num_turbines * turbine_rating_kilowatt / kilowatt_per_megawatt`` + * Get interconnect voltage - Get project size (project_size_megawatts = num_turbines * turbine_rating_kilowatt / kilowatt_per_megawatt) - Get interconnect voltage - - Return total substation costs + Keys in the input dictionary are the following: - \n\n**Keys in the input dictionary are the following:** + interconnect_voltage_kV : int + project interconnection voltage to substation [in kV + project_size_megawatts : int + total project size [in MW] - interconnect_voltage_kV - (int) project interconnection voltage to substation [in kV] + Keys in the output dictionary are the following: - project_size_megawatts - (int) total project size [in MW] - - \n\n**Keys in the output dictionary are the following:** - - substation_cost - (float) cost of substation [in USD] + substation_cost : float + cost of substation [in USD] + Created by Annika Eberle and Owen Roberts on Dec. 17, 2018 and refactored by Parangat Bhaskar and Alicia Key on June 3, 2019 """ def __init__(self, input_dict, output_dict, project_name): @@ -55,22 +48,21 @@ class documentation def calculate_costs(self, calculate_costs_input_dict , calculate_costs_output_dict): """ - Function to calculate Substation Cost in USD + Calculates the total substation cost in USD Parameters - ------- - interconnect_voltage_kV - (in kV) - - project_size_megawatts - (in MW) + ---------- + Uses the following from ``calculate_costs_input_dict`` + interconnect_voltage_kV : float + Interconnection voltage, in kV. + project_size_megawatts : float + Project capacity, in MW. - Returns: + Returns ------- - substation_cost - (in USD) - + substation_cost : float + Total substation cost, in USD. """ # Run in utility mode if number of turbines is > 10: @@ -95,11 +87,11 @@ 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() + Must be called after :py:meth:`run_module`. Returns ------- - list(dict) + list[dict] A list of dicts, with each dict representing a row of the data. """ result = [] @@ -127,10 +119,6 @@ def run_module(self): """ Runs the SubstationCost module and populates the IO dictionaries with calculated values. - Parameters - ---------- - - Returns ------- tuple diff --git a/landbosse/model/TransportCost.py b/landbosse/model/TransportCost.py index c564ffe8..c492edd9 100644 --- a/landbosse/model/TransportCost.py +++ b/landbosse/model/TransportCost.py @@ -7,26 +7,21 @@ class TransportCost(CostModule): """ - **TransportCost.py** - Calculates the costs associated with transportation for land-based wind projects *(module is currently based on curve fit of empirical data)* - Get number of blades, nacelles - - Return total trasnport costs - - \n\n**Keys in the input dictionary are the following:** + Gets the number of blades, nacelles, and returns total trasnport costs. - rotor_diameter_m - (float) Determines the approximate blade length [in m] + Keys in the input dictionary are the following: - number_turbines - (int) Number of turbines + rotor_diameter_m : float + Determines the approximate blade length [in m] + number_turbines : int + Number of turbines - \n\n**Keys in the output dictionary are the following:** + Keys in the output dictionary are the following: - transport_cost - (float) cost of transportation [in USD] + transport_cost : float + Cost of transportation [in USD] """ @@ -53,18 +48,15 @@ def calculate_costs(self, calculate_costs_input_dict, calculate_costs_output_dic Parameters ------- - interconnect_voltage_kV - (in kV) - - project_size_megawatts - (in MW) - + interconnect_voltage_kV : float + Interconnection voltage, in kV. + project_size_megawatts : float + Project capacity, in MW. - Returns: + Returns ------- - substation_cost - (in USD) - + substation_cost : float + Total cost, in USD. """ blade_length = 0.5 * calculate_costs_input_dict["rotor_diameter_m"] @@ -98,11 +90,11 @@ 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() + Must be called after :py:meth:`run_module`. Returns ------- - list(dict) + list[dict] A list of dicts, with each dict representing a row of the data. """ result = [] @@ -131,10 +123,6 @@ def run_module(self): """ Runs the TransportCost module and populates the IO dictionaries with calculated values. - Parameters - ---------- - - Returns ------- tuple diff --git a/landbosse/model/TurbineCost.py b/landbosse/model/TurbineCost.py index baa23408..dc65cbca 100644 --- a/landbosse/model/TurbineCost.py +++ b/landbosse/model/TurbineCost.py @@ -6,18 +6,12 @@ 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 + 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 """ @@ -44,11 +38,10 @@ def calculate_costs(self, calculate_costs_input_dict , calculate_costs_output_di Parameters ------- - turbine_capex - (in $/kW, default $1500/kW) - - number_turbines - (unitless) + turbine_capex: float + Turbe cost per nameplate capacity, in $/kW, default $1500/kW + number_turbine: int + Number of turbines. Returns: ------- @@ -79,7 +72,7 @@ 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() + Must be called after :py:meth:`run_module`. Returns ------- @@ -107,10 +100,6 @@ def run_module(self): """ Runs the TurbineCost module and populates the IO dictionaries with calculated values. - Parameters - ---------- - - Returns ------- tuple diff --git a/landbosse/model/WeatherDelay.py b/landbosse/model/WeatherDelay.py index 97116298..2b6fd01e 100644 --- a/landbosse/model/WeatherDelay.py +++ b/landbosse/model/WeatherDelay.py @@ -15,35 +15,30 @@ class WeatherDelay: or the number of hours at the start of the weather window--during which the work will not start. - The INPUT keys are the following: + The ``input_dict`` keys are the following: - weather_window - (pd.DataFrame) The weather window as prepared by the + weather_window : pd.DataFrame + The weather window as prepared by the read_weather_window function in the WeatherWindowCSVReader module. See the documentation for that function for details on the columns of the weather window. - - start_delay_hours - (float) Delay of mission from start of weather window. The weather + start_delay_hours : float + Delay of mission from start of weather window. The weather window is a list of hours with the weather values as rows. The delay can be as little as 0 hours or the total available construction hours for the project. - - mission_time_hours - (float) Length of mission. Mission length is the time it takes to + mission_time_hours : float + Length of mission. Mission length is the time it takes to complete the operation that may be delayed by the weather. + critical_wind_speed_m_per_s : float + Wind speed that the mission must shutdown and enter a delay state. + wind_height_of_interest_m : float + Height used in wind shear calculations. - critical_wind_speed_m_per_s - (float) Wind speed that the mission must shutdown and enter a delay state. - - - wind_height_of_interest_m - (float) Height used in wind shear calculations. + The ``output_dict`` keys are the following - The OUTPUT keys are the following - - wind_delay - (list) List of number of hours of each wind delay during the mission. + wind_delay : list + List of number of hours of each wind delay during the mission. length of list is number of weather delays. Value in list is duration of weather delay in hours. @@ -68,12 +63,6 @@ def validate_inputs(self, input_dict): necessary values needed for calculations in an instance of this class. It is made to validate input_dict dictionaries. - Returns - ------- - None - This method returns nothing if the validation passes. If it does - not pass an exception is raised. - Raises ------ ValueError diff --git a/pyproject.toml b/pyproject.toml index 6cfa57ed..780588af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "NREL-landbosse" dynamic = ["version"] description = "Wind-Plant Integrated System Design & Engineering Model" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.10" license = { text = "Apache-2.0" } keywords = ["wind", "turbine", "mdao", "design", "optimization"] authors = [ @@ -33,10 +33,11 @@ classifiers = [ # Optional # 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.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3 :: Only", "Programming Language :: C", "Programming Language :: Fortran", @@ -54,7 +55,7 @@ dependencies = ['numpy', 'openpyxl', 'pandas', 'scipy', 'xlsxwriter'] # projects. [project.optional-dependencies] # Optional test = ["coveralls", "pytest"] -docs = ["sphinx", "sphinx_rtd_theme"] +docs = ["jupyter-book==1.*", "myst-parser", "sphinxcontrib-napoleon"] # List URLs that are relevant to your project #