Full Code of NREL/floris for AI

main a0775339e325 cached
284 files
4.1 MB
1.1M tokens
1036 symbols
1 requests
Download .txt
Showing preview only (4,325K chars total). Download the full file or copy to clipboard to get everything.
Repository: NREL/floris
Branch: main
Commit: a0775339e325
Files: 284
Total size: 4.1 MB

Directory structure:
gitextract_8emkfpo1/

├── .codecov.yml
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── config.yml
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── check-working-examples.yaml
│       ├── continuous-integration-workflow.yaml
│       ├── deploy-pages.yaml
│       ├── python-publish.yml
│       └── quality-metrics-workflow.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── benchmarks/
│   └── bench.py
├── docs/
│   ├── .nojekyll
│   ├── _config.yml
│   ├── _toc.yml
│   ├── advanced_concepts.ipynb
│   ├── api_docs.md
│   ├── architecture.md
│   ├── bibliography.md
│   ├── code_quality.ipynb
│   ├── dev_guide.md
│   ├── empirical_gauss_model.md
│   ├── floating_wind_turbine.md
│   ├── floris_models.ipynb
│   ├── heterogeneous_map.ipynb
│   ├── index.md
│   ├── input_reference_main.md
│   ├── input_reference_turbine.md
│   ├── installation.md
│   ├── intro_concepts.ipynb
│   ├── layout_optimization.md
│   ├── multidimensional_wind_turbine.ipynb
│   ├── operation_models_user.ipynb
│   ├── references.bib
│   ├── turbine_library.md
│   ├── turbine_models.ipynb
│   ├── v3_to_v4.md
│   ├── wake_models.ipynb
│   └── wind_data_user.ipynb
├── examples/
│   ├── 001_opening_floris_computing_power.py
│   ├── 002_visualizations.py
│   ├── 003_wind_data_objects.py
│   ├── 004_set.py
│   ├── 005_getting_power.py
│   ├── 006_get_farm_aep.py
│   ├── 007_sweeping_variables.py
│   ├── 008_uncertain_models.py
│   ├── 009_parallel_models.py
│   ├── 010_compare_farm_power_with_neighbor.py
│   ├── _convert_examples_to_notebooks.py
│   ├── examples_control_optimization/
│   │   ├── 001_opt_yaw_single_ws.py
│   │   ├── 002_opt_yaw_single_ws_uncertain.py
│   │   ├── 003_opt_yaw_multiple_ws.py
│   │   ├── 004_optimize_yaw_aep.py
│   │   ├── 005_optimize_yaw_aep_parallel.py
│   │   ├── 006_compare_yaw_optimizers.py
│   │   ├── 007_optimize_yaw_with_neighbor_farms.py
│   │   └── 008_optimize_yaw_with_disabled_turbines.py
│   ├── examples_control_types/
│   │   ├── 001_derating_control.py
│   │   ├── 002_disable_turbines.py
│   │   ├── 003_setting_yaw_and_disabling.py
│   │   ├── 004_helix_active_wake_mixing.py
│   │   └── 005_peak_shaving.py
│   ├── examples_emgauss/
│   │   ├── 001_empirical_gauss_velocity_deficit_parameters.py
│   │   └── 002_empirical_gauss_deflection_parameters.py
│   ├── examples_floating/
│   │   ├── 001_floating_turbine_models.py
│   │   ├── 002_floating_vs_fixedbottom_farm.py
│   │   └── 003_tilt_driven_vertical_wake_deflection.py
│   ├── examples_get_flow/
│   │   ├── 001_extract_wind_speed_at_turbines.py
│   │   ├── 002_extract_wind_speed_at_points.py
│   │   ├── 003_extract_turbulence_intensity_at_points.py
│   │   └── 004_plot_velocity_deficit_profiles.py
│   ├── examples_heterogeneous/
│   │   ├── 001_heterogeneous_inflow_single.py
│   │   ├── 002_heterogeneous_using_wind_data.py
│   │   ├── 003_heterogeneous_speedup_by_wd_and_ws.py
│   │   └── 004_heterogeneous_2d_and_3d.py
│   ├── examples_layout_optimization/
│   │   ├── 001_optimize_layout.py
│   │   ├── 002_optimize_layout_with_heterogeneity.py
│   │   ├── 003_genetic_random_search.py
│   │   ├── 004_generate_gridded_layout.py
│   │   └── 005_layout_optimization_complex_boundary.py
│   ├── examples_load_optimization/
│   │   ├── 001_lti_and_voc.py
│   │   └── 002_row_opt_example.py
│   ├── examples_multidim/
│   │   ├── 001_multi_dimensional_cp_ct.py
│   │   ├── 002_multi_dimensional_cp_ct_2Hs.py
│   │   └── 003_multi_dimensional_cp_ct_TI.py
│   ├── examples_operation_models/
│   │   └── 001_compare_yaw_loss.py
│   ├── examples_turbine/
│   │   ├── 001_reference_turbines.py
│   │   ├── 002_multiple_turbine_types.py
│   │   └── 003_specify_turbine_power_curve.py
│   ├── examples_turbopark/
│   │   ├── 001_compare_turbopark_implementations.py
│   │   └── comparison_data/
│   │       ├── Rowpark_Orsted.csv
│   │       └── WindDirection_Sweep_Orsted.csv
│   ├── examples_uncertain/
│   │   ├── 001_uncertain_model_params.py
│   │   ├── 002_approx_floris_model.py
│   │   └── 003_uncertain_model_with_parallelization.py
│   ├── examples_visualizations/
│   │   ├── 001_layout_visualizations.py
│   │   ├── 002_visualize_y_cut_plane.py
│   │   ├── 003_visualize_cross_plane.py
│   │   ├── 004_visualize_rotor_values.py
│   │   └── 005_visualize_flow_by_sweeping_turbines.py
│   ├── examples_wind_data/
│   │   ├── 001_wind_data_comparisons.py
│   │   ├── 002_generate_ti.py
│   │   └── 003_generate_value.py
│   ├── examples_wind_resource_grid/
│   │   ├── 000_generate_example_wrg.py
│   │   ├── 001_wind_rose_wrg.py
│   │   ├── 002_set_floris_with_wrg.py
│   │   ├── 003_wrg_compar_layout_optimization.py
│   │   └── wrg_example.wrg
│   ├── inputs/
│   │   ├── cc.yaml
│   │   ├── emgauss.yaml
│   │   ├── emgauss_helix.yaml
│   │   ├── gch.yaml
│   │   ├── gch_heterogeneous_inflow.yaml
│   │   ├── gch_multi_dim_cp_ct.yaml
│   │   ├── gch_multi_dim_cp_ct_TI.yaml
│   │   ├── gch_multiple_turbine_types.yaml
│   │   ├── jensen.yaml
│   │   ├── turbine_files/
│   │   │   ├── iea_15MW_multi_dim_TI.csv
│   │   │   └── iea_15MW_multi_dim_TI.yaml
│   │   ├── turbopark.yaml
│   │   ├── turbopark_cubature.yaml
│   │   ├── turboparkgauss.yaml
│   │   ├── turboparkgauss_cubature.yaml
│   │   └── wind_rose.csv
│   └── inputs_floating/
│       ├── emgauss_fixed.yaml
│       ├── emgauss_floating.yaml
│       ├── emgauss_floating_fixedtilt15.yaml
│       ├── emgauss_floating_fixedtilt5.yaml
│       ├── gch_fixed.yaml
│       ├── gch_floating.yaml
│       ├── gch_floating_defined_floating.yaml
│       └── turbine_files/
│           ├── nrel_5MW_fixed.yaml
│           ├── nrel_5MW_floating.yaml
│           ├── nrel_5MW_floating_defined_floating.yaml
│           ├── nrel_5MW_floating_fixedtilt15.yaml
│           └── nrel_5MW_floating_fixedtilt5.yaml
├── floris/
│   ├── __init__.py
│   ├── convert_floris_input_v3_to_v4.py
│   ├── convert_turbine_v3_to_v4.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── core.py
│   │   ├── farm.py
│   │   ├── flow_field.py
│   │   ├── grid.py
│   │   ├── rotor_velocity.py
│   │   ├── solver.py
│   │   ├── turbine/
│   │   │   ├── __init__.py
│   │   │   ├── controller_dependent_operation_model.py
│   │   │   ├── operation_models.py
│   │   │   ├── turbine.py
│   │   │   └── unified_momentum_model.py
│   │   ├── wake.py
│   │   ├── wake_combination/
│   │   │   ├── __init__.py
│   │   │   ├── fls.py
│   │   │   ├── max.py
│   │   │   └── sosfs.py
│   │   ├── wake_deflection/
│   │   │   ├── __init__.py
│   │   │   ├── empirical_gauss.py
│   │   │   ├── gauss.py
│   │   │   ├── jimenez.py
│   │   │   └── none.py
│   │   ├── wake_turbulence/
│   │   │   ├── __init__.py
│   │   │   ├── crespo_hernandez.py
│   │   │   ├── none.py
│   │   │   └── wake_induced_mixing.py
│   │   └── wake_velocity/
│   │       ├── __init__.py
│   │       ├── cumulative_gauss_curl.py
│   │       ├── empirical_gauss.py
│   │       ├── gauss.py
│   │       ├── jensen.py
│   │       ├── none.py
│   │       ├── turbopark.py
│   │       ├── turbopark_lookup_table.mat
│   │       └── turboparkgauss.py
│   ├── cut_plane.py
│   ├── default_inputs.yaml
│   ├── floris_model.py
│   ├── flow_visualization.py
│   ├── heterogeneous_map.py
│   ├── layout_visualization.py
│   ├── logging_manager.py
│   ├── optimization/
│   │   ├── __init__.py
│   │   ├── layout_optimization/
│   │   │   ├── __init__.py
│   │   │   ├── layout_optimization_base.py
│   │   │   ├── layout_optimization_boundary_grid.py
│   │   │   ├── layout_optimization_gridded.py
│   │   │   ├── layout_optimization_pyoptsparse.py
│   │   │   ├── layout_optimization_pyoptsparse_spread.py
│   │   │   ├── layout_optimization_random_search.py
│   │   │   └── layout_optimization_scipy.py
│   │   ├── load_optimization/
│   │   │   ├── __init__.py
│   │   │   └── load_optimization.py
│   │   ├── other/
│   │   │   ├── __init__.py
│   │   │   └── boundary_grid.py
│   │   └── yaw_optimization/
│   │       ├── __init__.py
│   │       ├── yaw_optimization_base.py
│   │       ├── yaw_optimization_tools.py
│   │       ├── yaw_optimizer_geometric.py
│   │       ├── yaw_optimizer_scipy.py
│   │       └── yaw_optimizer_sr.py
│   ├── par_floris_model.py
│   ├── parallel_floris_model.py
│   ├── turbine_library/
│   │   ├── __init__.py
│   │   ├── demo_cp_ct_surfaces/
│   │   │   ├── iea_10MW_demo_cp_ct_surface.npz
│   │   │   ├── iea_15MW_demo_cp_ct_surface.npz
│   │   │   └── nrel_5MW_demo_cp_ct_surface.npz
│   │   ├── iea_10MW.yaml
│   │   ├── iea_15MW.yaml
│   │   ├── iea_15MW_floating_multi_dim_cp_ct.yaml
│   │   ├── iea_15MW_multi_dim_TI_u.csv
│   │   ├── iea_15MW_multi_dim_Tp_Hs.csv
│   │   ├── iea_15MW_multi_dim_cp_ct.yaml
│   │   ├── iea_22MW.yaml
│   │   ├── nrel_5MW.yaml
│   │   ├── turbine_previewer.py
│   │   └── turbine_utilities.py
│   ├── type_dec.py
│   ├── uncertain_floris_model.py
│   ├── utilities.py
│   └── wind_data.py
├── profiling/
│   ├── linux_perf.py
│   ├── profiling.py
│   ├── quality_metrics.py
│   ├── serial_vectorize.py
│   └── timing.py
├── pyproject.toml
└── tests/
    ├── __init__.py
    ├── base_unit_test.py
    ├── conftest.py
    ├── controller_dependent_operation_model_unit_test.py
    ├── convert_v3_to_v4_test.py
    ├── core_unit_test.py
    ├── data/
    │   ├── __init__.py
    │   ├── input_full.yaml
    │   ├── nrel_5MW_custom.yaml
    │   ├── wind_rose.csv
    │   ├── wind_ti_rose.csv
    │   └── wrg_test.wrg
    ├── farm_unit_test.py
    ├── floris_model_integration_test.py
    ├── flow_field_unit_test.py
    ├── geometric_yaw_unit_test.py
    ├── heterogeneous_map_integration_test.py
    ├── layout_optimization_integration_test.py
    ├── layout_visualization_test.py
    ├── load_optimization_test.py
    ├── par_floris_model_unit_test.py
    ├── parallel_floris_model_integration_test.py
    ├── reg_tests/
    │   ├── cumulative_curl_regression_test.py
    │   ├── empirical_gauss_regression_test.py
    │   ├── gauss_regression_test.py
    │   ├── jensen_jimenez_regression_test.py
    │   ├── none_regression_test.py
    │   ├── random_search_layout_opt_regression_test.py
    │   ├── scipy_layout_opt_regression.py
    │   ├── turbopark_regression_test.py
    │   ├── turboparkgauss_regression_test.py
    │   ├── turbulence_models_regression_test.py
    │   └── yaw_optimization_regression_test.py
    ├── rotor_velocity_unit_test.py
    ├── serial_refine_unit_test.py
    ├── turbine_grid_unit_test.py
    ├── turbine_multi_dim_unit_test.py
    ├── turbine_operation_models_unit_test.py
    ├── turbine_unit_test.py
    ├── turbine_utilities_unit_test.py
    ├── turboparkgauss_unit_test.py
    ├── type_dec_unit_test.py
    ├── uncertain_floris_model_integration_test.py
    ├── unified_momentum_operation_model_unit_test.py
    ├── utilities_unit_test.py
    ├── v3_to_v4_convert_test/
    │   ├── gch.yaml
    │   └── nrel_5MW_v3.yaml
    ├── wake_unit_tests.py
    ├── wind_data_integration_test.py
    ├── wind_rose_wrg_test.py
    └── yaw_optimization_integration_test.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .codecov.yml
================================================
# Codecov configuration file

comment: false

coverage:
    range: 0..100  # sets the range for the color bar in the dashboard
    round: down
    precision: 2
    status:
        project:
            default:
                # allow coverage to drop by this amount and still post success
                threshold: 10
        patch:
            default:
                threshold: 10

ignore:
    - "setup.py"
    - "tests/"


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Report a bug to help us improve
title: 'Bug report'
labels: "Type: Bug"
---

<!--
IMPORTANT NOTES

Thank you for taking the time to report a bug. If you aren't certain whether an issue
is a bug, please first open a Discussion. Before submitting, please reread your
description to ensure that other readers can reasonably understand the issue
you're facing and the impact on your workflow or results.

This form is written in GitHub's Markdown format. For a reference on this type
of syntax, see GitHub's documentation:
https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax

This template contains guidance for your submission within the < ! - -, - - > blocks.
These are comments in HTML syntax and will not appear in the submission.
Be sure to use the "Preview" feature on GitHub to ensure your submission is formatted as intended.

When including code snippets, please paste the text itself and wrap the code block with
ticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.
For example, Python code should be wrapped in ticks like this:
```python
def a_func():
    return 1

a = 1
b = a_func()
print(a + b)
```
This is preferred over screen shots since it is searchable and others can copy/paste
the text to run it.
-->

# Add meaningful title here
<!--
A clear and concise description of the bug including what happened
and what you expected to happen.
-->

## How to reproduce
<!--
Describe how another person with no context can recreate this issue.
It is typically very helpful to reduce the problem as much as possible
and share a minimum working example. See the note above on including
code as text rather than screenshots.
-->

## Relevant output
<!--
Include any output, plots, or other means of communication here to add context to the problem.
 -->

## Floris version
<!--
Share your floris version and how you installed it. You can print the floris version from
a Python REPL or script with these commands:
```python
import floris
print(floris.__version__)
```
 -->

## System Information
<!-- Add your information here. -->
 - OS: <e.g. Ubuntu 20.04 or macOS 10.12>
 - Python version: <Result of `python --version`>
 - Library versions
   - Results of `pip freeze`, for example
   - matplotlib
   - numpy
   - numexpr
   - scipy
   - pandas


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: Usage question
    url: https://github.com/NatLabRockies/floris/discussions
    about: Have any questions about using FLORIS? Post in Discussions to engage with the NLR team and FLORIS community.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: 'Feature request'
labels: 'Type: Enhancement'
---

<!--
IMPORTANT NOTES

Thank you for taking the time to suggest a feature. Before submitting,
please reread your description to ensure that other readers can reasonably
understand the motivation and proposed solution.

This form is written in GitHub's Markdown format. For a reference on this type
of syntax, see GitHub's documentation:
https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax

This template contains guidance for your submission within the < ! - -, - - > blocks.
These are comments in HTML syntax and will not appear in the submission.
Be sure to use the "Preview" feature on GitHub to ensure your submission is formatted as intended.

When including code snippets, please paste the text itself and wrap the code block with
ticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.
For example, Python code should be wrapped in ticks like this:
```python
def a_func():
    return 1

a = 1
b = a_func()
print(a + b)
```
This is preferred over screen shots since it is searchable and others can copy/paste
the text to run it.
-->

# Add meaningful title here
<!--
High level description of the feature request including motivation and background.
-->

## Proposed solution
<!--
Here's an opportunity to prototype a feature. Please include pseudocode, images, or
any other visual aids to communicate the idea.
-->

## Alternatives considered
<!--
Describe workarounds or alternatives even if hacky or incomplete.
-->

## Additional context
<!--
Optional. Provide anything else that helps to communicate the idea here.
-->


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================

<!--
IMPORTANT NOTES

Is this pull request ready to be merged?
- Do the existing tests pass and new tests added for new code?
- Is all development in a state where you are proud to share it with others and
  willing to ask other people to take the time to review it?
- Is it documented in such a way that a review can reasonably understand what you've
  done and why you've done it? Can other users understand how to use your changes?
If not but opening the pull request will facilitate development, make it a "draft" pull request

This form is written in GitHub's Markdown format. For a reference on this type
of syntax, see GitHub's documentation:
https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax

This template contains guidance for your submission within the < ! - -, - - > blocks.
These are comments in HTML syntax and will not appear in the submission.
Be sure to use the "Preview" feature on GitHub to ensure your submission is formatted as intended.

When including code snippets, please paste the text itself and wrap the code block with
ticks (see the other character on the tilde ~ key in a US keyboard) to format it as code.
For example, Python code should be wrapped in ticks like this:
```python
def a_func():
    return 1

a = 1
b = a_func()
print(a + b)
```
This is preferred over screen shots since it is searchable and others can copy/paste
the text to run it.
-->


# Add meaningful title here
<!--
Be sure to title your pull request so that readers can scan through the list of PR's and understand
what this one involves. It should be a few well selected words to get the point across. If you have
a hard time choosing a brief title, consider splitting the pull request into multiple pull requests.
Keep in mind that the title will be automatically included in the release notes.
-->
Describe your feature here.

## Related issue
<!--
If one exists, link to a related GitHub Issue.
-->

## Impacted areas of the software
<!--
List any modules or other areas which should be impacted by this pull request. This helps to determine the verification tests.
-->

## Additional supporting information
<!--
Add any other context about the problem here.
-->

## Test results, if applicable
<!--
Add the results from unit tests and regression tests here along with justification for any failing test cases.
-->

<!--
__ For NLR use __
Release checklist:
- Update the version in
    - [ ] README.md (appears twice in README.md)
    - [ ] pyproject.toml
- [ ] Verify docs builds correctly
- [ ] Create a tag in the NREL/FLORIS repository
-->


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: "pip"
  directory: "/" # Location of package manifests
  target-branch: "develop"
  schedule:
    interval: "monthly"
  labels:
    - "package"
  ignore:
    - dependency-name: "*"
      update-types: ["version-update:semver-minor", "version-update:semver-patch"]


================================================
FILE: .github/workflows/check-working-examples.yaml
================================================
name: Check Examples APIs

on: [push, pull_request]

jobs:

  examples-check:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        python-version: ["3.10", "3.14"]
        os: [ubuntu-latest]
      fail-fast: False

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install project
      run: |
        python -m pip install --upgrade pip
        pip install .
        pip install nbconvert  # For converting Jupyter notebook to python script in the next step

    - name: Run examples (ubuntu, macos)
      # Run all examples and test that they finish successfully. Do not evaluate the results.
      # Copy the examples to a new directory outside of the repo to ensure that there is no
      # reliance on the repo directory structure.
      run: |
        mkdir -p temp1/temp2/temp3
        cp -rL examples temp1/temp2/temp3/.
        cd temp1/temp2/temp3/examples/

        error_found=0  # 0 is false
        error_results="Error in example:"

        # Now run the examples in root and  subdirectories
        echo "Running examples"
        for d in . $(find . -type d -name "*examples*"); do
          cd $d
          echo "========================= Example directory- $d"
          for i in *.py; do
            echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Running example- $i"

            # If "convert_examples" is in i, skip this script
            if [[ $i == *"convert_examples"* ]]; then
              continue
            fi

            if ! python $i; then
              error_results="${error_results}"$'\n'" - ${i}"
              error_found=1
            fi
          done
          if [ "$d" != "." ]; then
            cd ..
          fi

        done

        if [[ $error_found ]]; then
          echo "${error_results}"
        fi

        exit $error_found


================================================
FILE: .github/workflows/continuous-integration-workflow.yaml
================================================
name: Automated tests & code coverage

on: [push, pull_request]

jobs:

  code-qa-validation:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
        os: [ubuntu-latest, macos-latest, windows-latest]
      fail-fast: False
    env:
      CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install project
      run: |
        python -m pip install --upgrade pip
        pip install ".[develop]"
    - uses: pre-commit/action@v3.0.0
    - name: Run tests (ubuntu, macos)
      if: matrix.os != 'windows-latest' && (success() || failure())  # Run this step even if the linting step fails
      run: |
        mkdir -p temp1/temp2/temp3
        cp -rL tests temp1/temp2/temp3/.
        cd temp1/temp2/temp3/

        # -rA displays the captured output for all tests after they're run
        # See the docs: https://doc.pytest.org/en/latest/reference/reference.html#command-line-flags
        pytest -rA tests/ --ignore tests/timing.py --ignore tests/profiling.py
    - name: Run tests (windows)
      if: matrix.os == 'windows-latest' && (success() || failure())  # Run this step even if the linting step fails
      run: |
        mkdir -p temp1/temp2/temp3
        cp -r tests temp1/temp2/temp3/.
        cd temp1/temp2/temp3/

        # -rA displays the captured output for all tests after they're run
        # See the docs: https://doc.pytest.org/en/latest/reference/reference.html#command-line-flags
        pytest -rA tests/ --ignore tests/timing.py --ignore tests/profiling.py
    - name: Generate coverage report
      # Run these tests on unit tests only so that we avoid inflating our code
      # coverage through the regression tests
      if: matrix.os == 'ubuntu-latest'
      run: |
        pip install pytest
        pip install pytest-cov
        pytest --cov=./ --cov-report=xml tests/ --ignore tests/reg_tests --ignore tests/timing.py --ignore tests/profiling.py
    - name: Upload coverage to Codecov
      if: ${{ matrix.os == 'ubuntu-latest' && env.CODECOV_TOKEN }}  # Don't attempt to upload if the codecov token is not configured
      uses: codecov/codecov-action@v3
      with:
        token: ${{ env.CODECOV_TOKEN }}
        files: ./coverage.xml
        fail_ci_if_error: true


================================================
FILE: .github/workflows/deploy-pages.yaml
================================================
name: deploy-pages

on:
  push:
    branches:
    - develop


  workflow_dispatch:  # Allows manual triggering of the workflow

# This job installs dependencies, builds the book, and pushes it to `gh-pages`
jobs:
  deploy-book:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    # Install dependencies
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: "3"

    - name: Install dependencies
      run: |
        pip install -e ".[docs, develop]"

    # Make a copy of the examples folder within the docs folder
    - name: Copy examples to docs
      working-directory: ${{runner.workspace}}/floris/
      run: |
        rsync -av examples/ docs/examples
        ls docs/examples

    # Run the script examples/_convert_examples_to_notebooks.py
    - name: Convert examples to notebooks
      working-directory: ${{runner.workspace}}/floris/docs/examples/
      run: |
        pwd
        ls
        python _convert_examples_to_notebooks.py

    # Build the book
    - name: Build the book
      working-directory: ${{runner.workspace}}/floris/docs/
      run: |
        jupyter-book build .

    # Push the book's HTML to github-pages
    - name: GitHub Pages action
      uses: peaceiris/actions-gh-pages@v4.0.0
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./docs/_build/html

    # Stash changes before benchmark action
    - name: Stash changes
      working-directory: ${{runner.workspace}}/floris/
      run: |
        git stash

    - name: Run benchmark
      working-directory: ${{runner.workspace}}/floris/
      run: |
        ls -lah
        cd benchmarks
        pytest bench.py --benchmark-json output.json

    # Store benchmark result and create the benchmark pages
    # Update the index.html and data.js files in the
    # dev/bench folder of the benches branch
    # dev/bench is the default folder for pytest-benchmark
    - name: Store benchmark result
      uses: benchmark-action/github-action-benchmark@v1
      with:
        name: Python Benchmark with pytest-benchmark
        tool: 'pytest'
        output-file-path: benchmarks/output.json
        github-token: ${{ secrets.GITHUB_TOKEN }}
        auto-push: true
        gh-pages-branch: benches

    # Add bench mark files to the gh-pages branch
    - name: Add benchmark files to gh-pages
      working-directory: ${{runner.workspace}}/floris/
      run: |
        ls -lah
        git config --global user.email "github-actions[bot]@users.noreply.github.com"
        git config --global user.name "github-actions[bot]"
        git fetch origin benches
        git checkout benches
        rsync -av dev/bench /tmp/bench
        git fetch origin gh-pages
        git checkout gh-pages
        mkdir -p dev
        rsync -av /tmp/bench/ dev/
        ls -lah dev/bench
        git add dev
        git commit -m "Add bench folder to gh-pages"
        git push origin gh-pages


================================================
FILE: .github/workflows/python-publish.yml
================================================
# This workflows will upload a Python Package using Twine when a release is created
# Published via GitHub Actions as a PyPI Trusted Publisher.
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
# and: https://docs.pypi.org/trusted-publishers/

name: Upload Python Package

on:
  release:
    types: [published]

jobs:
  deploy:
    environment: release-pypi
    if: github.repository_owner == 'NatLabRockies'
    runs-on: ubuntu-latest
    permissions:
      id-token: write
    steps:
      - uses: actions/checkout@v6
      - name: Set up Python
        uses: actions/setup-python@v6
        with:
          python-version: '3.x'
      - name: Install dependencies and build package
        run: |
          python -m pip install --upgrade pip
          pip install build twine
          python -m build
          twine check --strict dist/*
      - name: Publish package to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          verbose: True


================================================
FILE: .github/workflows/quality-metrics-workflow.yaml
================================================
name: Code Quality Check

on: [push, pull_request]

jobs:

  code-qa-validation:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        python-version: ["3.13"]
        os: [ubuntu-latest]
      fail-fast: False

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install project
      run: |
        python -m pip install --upgrade pip
        pip install ".[develop]"
    - name: Run the code quality script
      run: |
        cd profiling
        python quality_metrics.py


================================================
FILE: .gitignore
================================================

# python compiled files
__pycache__/
.cache
*.ipynb
*.ipynb_checkpoints
*.pyc
*.egg-info
dist
build
.pytest_cache
.ruff_cache

# pip meta data
pip-wheel-metadata

# macOS files
.DS_Store

# IDE settings and files
.idea
.vscode

# Documentation notebooks
!docs/*.ipynb

# The examples folder within docs
docs/examples

# Documentation output
_site/
.jekyll-cache/
_build
_autosummary/

# Output from examples
examples/cp_ct_cq_lut.p
examples/hist.hist
examples/SLSQP.out

# Log files
*.log

# Temp files in convert test
tests/v3_to_v4_convert_test/convert_turbine_v3_to_v4.py
tests/v3_to_v4_convert_test/convert_floris_input_v3_to_v4.py
tests/v3_to_v4_convert_test/gch_v4.yaml
tests/v3_to_v4_convert_test/nrel_5MW_v3_v4.yaml


================================================
FILE: .pre-commit-config.yaml
================================================

repos:

- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.4.0
  hooks:
  - id: trailing-whitespace
  - id: end-of-file-fixer
  - id: check-executables-have-shebangs
  - id: check-yaml
    args: [--unsafe]
  - id: check-merge-conflict
  - id: check-symlinks
  - id: mixed-line-ending

- repo: https://github.com/charliermarsh/ruff-pre-commit
  rev: v0.9.6
  hooks:
  - id: ruff

- repo: https://github.com/timothycrosley/isort
  rev: 5.12.0
  hooks:
  - id: isort
    name: isort
    stages: [commit]


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to FLORIS

FLORIS is a community model, and we are excited for community contributions!
There are a variety of ways in which you can contribute beyond writing code.
This document provides a high-level overview of how you can get involved.


## Asking Questions

Have a question? Rather than opening an issue directly, please ask questions
or post comments in [Q&A Discussions](https://github.com/NatLabRockies/floris/discussions/categories/q-a).
The NLR team or other members of the community will assist. Your well-worded
question will serve as a resource to others searching for help.


## Providing Feedback

Your comments and feedback are very welcome. Please post to
[General Discussions](https://github.com/NatLabRockies/floris/discussions/categories/general)
with lots of information and detail. It is beneficial to consider
how someone else will understand your comments in order to make
them most effective.


## Reporting Issues

Have you identified a reproducible problem in FLORIS?
Have a feature request? We want to hear about it! Here's how you can make
reporting your issue as effective as possible.

### Look For an Existing Issue

Before you create a new issue, please do a search in
[open issues](https://github.com/microsoft/vscode/issues) to see if
the issue or feature request has already been filed.

If you find your issue already exists, make relevant comments and add your
[reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments).
Use a reaction in place of a "+1" comment:

- 👍 - upvote
- 👎 - downvote

If you cannot find an existing issue that describes your bug or feature,
create a new issue using the guidelines below.

### Writing Good Bug Reports and Feature Requests

File a single issue per problem and feature request. Do not enumerate
multiple bugs or feature requests in the same issue.

Do not add your issue as a comment to an existing issue unless it's for the
identical input. Many issues look similar, but have different causes.

The more information you can provide, the more likely someone will
be successful at reproducing the issue and finding a fix.

Please follow the issue template guidelines to include relevant information
that will help in diagnosing the problem.

### Final Checklist

Please remember to do the following:

- [ ] Search the issue repository to ensure your report is a new issue

- [ ] Recreate the issue with a minimally descriptive example

- [ ] Simplify your code around the issue to better isolate the problem


## Contributing Fixes

If you are interested in writing code to fix an issue or
submit a new feature, let us know in
[Ideas Discussions](https://github.com/NatLabRockies/floris/discussions/categories/ideas)!

We rely heavily on git and GitHub, so be sure to review the
contributing guidelines in the
[online documentation](https://natlabrockies.github.io/floris/dev_guide.html).


================================================
FILE: LICENSE.txt
================================================
BSD 3-Clause License

Copyright (c) 2025, Alliance for Energy Innovation LLC, All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions
and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution.

* Neither the name of the copyright holder nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
# FLORIS Wake Modeling and Wind Farm Controls Software

FLORIS is a controls-focused wind farm simulation software incorporating
steady-state engineering wake models into a performance-focused Python
framework. It has been in active development at NLR since 2013 and the latest
release is [FLORIS v.4.6.4](https://github.com/NatLabRockies/floris/releases/latest).
Online documentation is available at https://natlabrockies.github.io/floris.

The software is in active development and engagement with the development team
is highly encouraged. If you are interested in using FLORIS to conduct studies
of a wind farm or extending FLORIS to include your own wake model, please join
the conversation in [GitHub Discussions](https://github.com/NatLabRockies/floris/discussions/)!

## WETO software

FLORIS is primarily developed with the support from the U.S. Department of Energy and
is part of the [WETO Software Stack](https://natlabrockies.github.io/WETOStack).
For more information and other integrated modeling software, see:

- [Portfolio Overview](https://natlabrockies.github.io/WETOStack/portfolio_analysis/overview.html)
- [Entry Guide](https://natlabrockies.github.io/WETOStack/_static/entry_guide/index.html)
- [Wind Farm Controls Workshop](https://www.youtube.com/watch?v=f-w6whxIBrA&list=PL6ksUtsZI1dwRXeWFCmJT6cEN1xijsHJz)

## Installation

**If upgrading from a previous version, it is recommended to install FLORIS v4 into a new virtual environment**.
If you intend to use [pyOptSparse](https://mdolab-pyoptsparse.readthedocs-hosted.com/en/latest/) with FLORIS,
it is recommended to install that package first before installing FLORIS.

FLORIS can be installed by downloading the source code or via the PyPI
package manager with `pip`.

The simplest method is with `pip` by using this command:

```bash
pip install floris
```

Developers and anyone who intends to inspect the source code
can install FLORIS by downloading the git repository
from GitHub with ``git`` and use ``pip`` to locally install it.
It is highly recommended to use a Python virtual environment manager
such as [conda](https://docs.conda.io/en/latest/miniconda.html)
in order to maintain a clean and sandboxed environment. The following
commands in a terminal or shell will download and install FLORIS.

```bash
    # Download the source code from the `main` branch
    git clone -b main https://github.com/NatLabRockies/floris.git

    # If using conda, be sure to activate your environment prior to installing
    # conda activate <env name>

    # If using pyOptSpare, install it first
    conda install -c conda-forge pyoptsparse

    # Install FLORIS
    pip install -e floris
```

With both methods, the installation can be verified by opening a Python interpreter
and importing FLORIS:

```python
>>> import floris
>>> help(floris)

Help on package floris:

NAME
    floris

PACKAGE CONTENTS
    convert_floris_input_v3_to_v4
    convert_turbine_v3_to_v4
    core (package)
    cut_plane
    floris_model
    flow_visualization
    layout_visualization
    logging_manager
    optimization (package)
    parallel_floris_model
    turbine_library (package)
    type_dec
    uncertain_floris_model
    utilities
    version
    wind_data

VERSION
    4.6.4

FILE
    ~/floris/floris/__init__.py
```

It is important to regularly check for new updates and releases as new
features, improvements, and bug fixes will be issued on an ongoing basis.

## Quick Start

FLORIS is a Python package run on the command line typically by providing
an input file with an initial configuration. It can be installed with
```pip install floris``` (see [installation](https://natlabrockies.github.io/floris/installation.html)).
The typical entry point is
[FlorisModel](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html)
which accepts the path to the input file as an argument. From there,
changes can be made to the initial configuration through the
[FlorisModel.set](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.set)
routine, and the simulation is executed with
[FlorisModel.run](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.run).

```python
from floris import FlorisModel
fmodel = FlorisModel("path/to/input.yaml")
fmodel.set(
    wind_directions=[i for i in range(10)],
    wind_speeds=[8.0]*10,
    turbulence_intensities=[0.06]*10
)
fmodel.run()
```

Finally, results can be analyzed via post-processing functions available within
[FlorisModel](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel)
such as
- [FlorisModel.get_turbine_layout](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.get_turbine_layout)
- [FlorisModel.get_turbine_powers](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.get_turbine_powers)
- [FlorisModel.get_farm_AEP](https://natlabrockies.github.io/floris/_autosummary/floris.floris_model.html#floris.floris_model.FlorisModel.get_farm_AEP)

and in two visualization packages: [layoutviz](https://natlabrockies.github.io/floris/_autosummary/floris.layout_visualization.html) and [flowviz](https://natlabrockies.github.io/floris/_autosummary/floris.flow_visualization.html).
A collection of examples describing the creation of simulations as well as
analysis and post processing are included in the
[repository](https://github.com/NatLabRockies/floris/tree/main/examples). Examples are also listed
in the [online documentation](https://natlabrockies.github.io/floris/examples/001_opening_floris_computing_power.html).

## Engaging on GitHub

FLORIS leverages the following GitHub features to coordinate support and development efforts:

- [Discussions](https://github.com/NatLabRockies/floris/discussions): Collaborate to develop ideas for new use cases, features, and software designs, and get support for usage questions
- [Issues](https://github.com/NatLabRockies/floris/issues): Report potential bugs and well-developed feature requests
- [Projects](https://github.com/orgs/NREL/projects/96): Include current and future work on a timeline and assign a person to "own" it

Generally, the first entry point for the community will be within one of the
categories in Discussions.
[Ideas](https://github.com/NatLabRockies/floris/discussions/categories/ideas) is a great spot to develop the
details for a feature request. [Q&A](https://github.com/NatLabRockies/floris/discussions/categories/q-a)
is where to get usage support.
[Show and tell](https://github.com/NatLabRockies/floris/discussions/categories/show-and-tell) is a free-form
space to show off the things you are doing with FLORIS.


# License

BSD 3-Clause License

Copyright (c) 2025, Alliance for Energy Innovation LLC, All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions
and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution.

* Neither the name of the copyright holder nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: benchmarks/bench.py
================================================
from pathlib import Path

import numpy as np
import pytest

from floris import (
    FlorisModel,
    TimeSeries,
)
from floris.core.turbine.operation_models import POWER_SETPOINT_DEFAULT
from floris.heterogeneous_map import HeterogeneousMap


N_Conditions = 100

# These tests are run automatically by pytest-benchmark.  The benchmark
# object is passed to the test function.

def test_timing_small_farm_set(benchmark):
    """Timing test for setting up a small farm"""
    fmodel = FlorisModel(configuration="defaults")
    wind_directions = np.linspace(0, 360, N_Conditions)
    wind_speeds = np.ones(N_Conditions) * 8
    turbulence_intensities = np.ones(N_Conditions) * 0.06

    benchmark(
        fmodel.set,
        wind_directions=wind_directions,
        wind_speeds=wind_speeds,
        turbulence_intensities=turbulence_intensities,
        layout_x=np.linspace(0, 1000, 3),
        layout_y=np.linspace(0, 1000, 3),
    )


def test_timing_small_farm_run(benchmark):
    """Timing test for running a small farm"""
    fmodel = FlorisModel(configuration="defaults")
    wind_directions = np.linspace(0, 360, N_Conditions)
    wind_speeds = np.ones(N_Conditions) * 8
    turbulence_intensities = np.ones(N_Conditions) * 0.06

    fmodel.set(
        wind_directions=wind_directions,
        wind_speeds=wind_speeds,
        turbulence_intensities=turbulence_intensities,
        layout_x=np.linspace(0, 1000, 3),
        layout_y=np.linspace(0, 1000, 3),
    )

    benchmark(fmodel.run)


def test_timing_large_farm_set(benchmark):
    """Timing test for setting up a large farm"""
    fmodel = FlorisModel(configuration="defaults")
    wind_directions = np.linspace(0, 360, N_Conditions)
    wind_speeds = np.ones(N_Conditions) * 8
    turbulence_intensities = np.ones(N_Conditions) * 0.06

    benchmark(
        fmodel.set,
        wind_directions=wind_directions,
        wind_speeds=wind_speeds,
        turbulence_intensities=turbulence_intensities,
        layout_x=np.linspace(0, 10000, 100),
        layout_y=np.linspace(0, 10000, 100),
    )


def test_timing_large_farm_run(benchmark):
    """Timing test for running a large farm"""
    fmodel = FlorisModel(configuration="defaults")
    wind_directions = np.linspace(0, 360, N_Conditions)
    wind_speeds = np.ones(N_Conditions) * 8
    turbulence_intensities = np.ones(N_Conditions) * 0.06

    fmodel.set(
        wind_directions=wind_directions,
        wind_speeds=wind_speeds,
        turbulence_intensities=turbulence_intensities,
        layout_x=np.linspace(0, 10000, 100),
        layout_y=np.linspace(0, 10000, 100),
    )

    benchmark(fmodel.run)


def test_timing_het_set(benchmark):
    """Timing test for setting up a farm with a heterogeneous map"""

    # The side of the flow which is accelerated reverses for east versus west
    het_map = HeterogeneousMap(
        x=np.array([0.0, 0.0, 500.0, 500.0]),
        y=np.array([0.0, 500.0, 0.0, 500.0]),
        speed_multipliers=np.array(
            [
                [1.0, 2.0, 1.0, 2.0],  # Top accelerated
                [2.0, 1.0, 2.0, 1.0],  # Bottom accelerated
            ]
        ),
        wind_directions=np.array([270.0, 90.0]),
        wind_speeds=np.array([8.0, 8.0]),
    )

    # Get the FLORIS model
    fmodel = FlorisModel(configuration="defaults")

    time_series = TimeSeries(
        wind_directions=np.linspace(0, 360, N_Conditions),
        wind_speeds=8.0,
        turbulence_intensities=0.06,
        heterogeneous_map=het_map,
    )

    # Set the model to a turbines perpendicular to
    # east/west flow with 0 turbine closer to bottom and
    # turbine 1 closer to top
    benchmark(
        fmodel.set,
        wind_data=time_series,
        layout_x=[250.0, 250.0],
        layout_y=[100.0, 400.0],
    )


def test_timing_het_run(benchmark):
    """Timing test for running a farm with a heterogeneous map"""

    # The side of the flow which is accelerated reverses for east versus west
    het_map = HeterogeneousMap(
        x=np.array([0.0, 0.0, 500.0, 500.0]),
        y=np.array([0.0, 500.0, 0.0, 500.0]),
        speed_multipliers=np.array(
            [
                [1.0, 2.0, 1.0, 2.0],  # Top accelerated
                [2.0, 1.0, 2.0, 1.0],  # Bottom accelerated
            ]
        ),
        wind_directions=np.array([270.0, 90.0]),
        wind_speeds=np.array([8.0, 8.0]),
    )

    # Get the FLORIS model
    fmodel = FlorisModel(configuration="defaults")

    time_series = TimeSeries(
        wind_directions=np.linspace(0, 360, N_Conditions),
        wind_speeds=8.0,
        turbulence_intensities=0.06,
        heterogeneous_map=het_map,
    )

    # Set the model to a turbines perpendicular to
    # east/west flow with 0 turbine closer to bottom and
    # turbine 1 closer to top
    fmodel.set(
        wind_data=time_series,
        layout_x=[250.0, 250.0],
        layout_y=[100.0, 400.0],
    )

    benchmark(fmodel.run)


================================================
FILE: docs/.nojekyll
================================================


================================================
FILE: docs/_config.yml
================================================
# Book settings
# Learn more at https://jupyterbook.org/customize/config.html

title: FLORIS
author: National Laboratory of the Rockies
logo: docs_image.png
copyright: '2025'
only_build_toc_files: false

# Force re-execution of notebooks on each build.
# See https://jupyterbook.org/content/execute.html
execute:
  execute_notebooks: auto
  timeout: 420 # Give each notebook cell 7 minutes to execute

# 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/NatLabRockies/floris
  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
  use_edit_page_button: true
  analytics:
    google_analytics_id: G-JV2SK7CNPR


# Sphinx for API doc generation
sphinx:
  extra_extensions:
  - 'sphinx.ext.autodoc'
  - 'sphinx.ext.autosummary'
  - 'sphinx.ext.viewcode'
  - 'sphinx_autodoc_typehints'
  - 'sphinxcontrib.autoyaml'
  - 'sphinxcontrib.mermaid'
  config:
    language: 'python'
    nb_execution_show_tb: true          # Shows the stack trace in stdout; its suppressed otherwise.
    nb_execution_raise_on_error: true   # Stops the Sphinx build if there is an error in a notebook. See https://github.com/executablebooks/jupyter-book/issues/2011
    suppress_warnings:
    - etoc.toctree                      # autodoc output contains toctrees, so suppress this warning. See https://github.com/executablebooks/sphinx-external-toc/issues/36
    autoyaml_level: 3
    autosummary_generate: true

    # Autodoc config reference
    # https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#configuration
    autodoc_default_options:
      members: true
      member-order: bysource
      undoc-members: true
      private-members: false
      # special-members: true
      # inherited-members
      # show-inheritance
      # ignore-module-all
      # imported-members: true
      # exclude-members
      # class-doc-from
      # no-value
    autodoc_typehints: both
    mermaid_version: "10.8"


================================================
FILE: docs/_toc.yml
================================================
# Table of contents
# Learn more at https://jupyterbook.org/customize/toc.html

format: jb-book
root: index
parts:
  - caption: Getting Started
    chapters:
    - file: installation
    - file: v3_to_v4

  - caption: User Reference
    chapters:
    - file: intro_concepts
    - file: wind_data_user
    - file: floris_models
    - file: input_reference_main
    - file: turbine_models
      sections:
      - file: input_reference_turbine
      - file: operation_models_user
      - file: floating_wind_turbine
      - file: multidimensional_wind_turbine
      - file: turbine_library
    - file: advanced_concepts
    - file: heterogeneous_map
    - file: layout_optimization
    - file: examples

  - caption: Theory and Background
    chapters:
    - file: wake_models
      sections:
      - file: empirical_gauss_model
    - file: bibliography

  - caption: Developer Reference
    chapters:
    - file: dev_guide
    - file: architecture
    - file: code_quality
    - file: api_docs


================================================
FILE: docs/advanced_concepts.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(concepts_advanced)=\n",
    "\n",
    "# Advanced Concepts\n",
    "\n",
    "More information regarding the numerical and computational formulation in FLORIS\n",
    "are detailed here. See [Introductory Concepts](intro_concepts) for a guide on the basics."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create a basic FLORIS model for use later\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from floris import FlorisModel\n",
    "fmodel = FlorisModel(\"gch.yaml\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data structures\n",
    "\n",
    "FLORIS adopts a structures of arrays data modeling paradigm (SoA, relative to array of structures {AoS})\n",
    "for nearly all of the data in the `floris.core` package.\n",
    "This data model enables vectorization (SIMD operations) through Numpy array broadcasting\n",
    "for many operations.\n",
    "In general, there are two types of array shapes:\n",
    "- Field quantities have points throughout the computational domain but in context-specific locations\n",
    "    and have the shape `(n findex, n turbines, n grid, n grid)`.\n",
    "- Scalar quantities have a single value for each turbine and typically have the shape\n",
    "    `(n findex, n turbines, 1, 1)`. For scalar quanities, the arrays\n",
    "    may be created with the shape `(n findex, n turbines)` and\n",
    "    then expanded to the 4-dimensional shape prior to running the wake calculation."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Grids\n",
    "\n",
    "FLORIS includes a number of grid-types that create sampling points within the computational\n",
    "domain for different contexts. In the typical use case, AEP or some other metric of wind\n",
    "farm energy yield is the end result. Since the mathematical models in FLORIS are all\n",
    "analytical, we only need to create points on the turbines themselves in order to calculate\n",
    "the incoming wind speeds given all of the upstream conditions. In this case, we use\n",
    "the {py:meth}`floris.core.grid.TurbineGrid` or {py:meth}`floris.core.grid.TurbineCubatureGrid`.\n",
    "Each of these grid-types put points only on the turbine swept area, so all other\n",
    "field-quantities in FLORIS have the same shape."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot the grid point locations for TurbineGrid and TurbineCubatureGrid\n",
    "\n",
    "fmodel.set(layout_x=[0.0], layout_y=[0.0])\n",
    "rotor_radius = fmodel.core.farm.rotor_diameters[0] / 2.0\n",
    "hub_height = fmodel.core.farm.hub_heights[0]\n",
    "theta = np.linspace(0, 2*np.pi, 100)\n",
    "circlex = rotor_radius * np.cos(theta)\n",
    "circley = rotor_radius * np.sin(theta) + hub_height\n",
    "\n",
    "# TurbineGrid is the default\n",
    "fig, ax = plt.subplots()\n",
    "ax.scatter(0, hub_height, marker=\"+\", color=\"r\")\n",
    "ax.scatter(fmodel.core.grid.y_sorted[0,0], fmodel.core.grid.z_sorted[0,0], marker=\"+\", color=\"r\")\n",
    "ax.plot(circlex, circley)\n",
    "ax.set_aspect('equal', 'box')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## FLORIS as a library\n",
    "\n",
    "FLORIS is commonly used as a library in other software packages.\n",
    "In cases where the calling-code will create inputs for FLORIS rather than require them from the\n",
    "user, it can be helpful to initialize the FLORIS model with default inputs and then\n",
    "change them in code.\n",
    "In this case, the following workflow is recommended."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import floris\n",
    "\n",
    "# Initialize FLORIS with defaults\n",
    "fmodel = floris.FlorisModel(\"defaults\")\n",
    "\n",
    "# Within the calling-code's setup step, update FLORIS as needed\n",
    "fmodel.set(\n",
    "    wind_directions=[i for i in range(10)],\n",
    "    wind_speeds=[5 + i for i in range(10)],\n",
    "    turbulence_intensities=[i for i in range(10)],\n",
    "    # turbine_library_path=\"path/to/turbine_library\",   # Shown here for reference\n",
    "    # turbine_type=[\"my_turbine\"]\n",
    ")\n",
    "\n",
    "# Within the calling code's computation, run FLORIS\n",
    "fmodel.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, the calling-code can import the FLORIS default inputs as a Python dictionary\n",
    "and modify them directly before initializing the FLORIS model.\n",
    "This is especially helpful when the calling-code will modify a parameter that isn't\n",
    "supported by the `FlorisModel.set(...)` command.\n",
    "In particular, the wake model parameters are not directly accessible, so these can be updated\n",
    "externally, as shown below.\n",
    "Note that the `FlorisModel.get_defaults()` function returns a deep copy of the default inputs,\n",
    "so these can be modified directly without side effects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "solver\n",
      "    type\n",
      "        turbine_grid\n",
      "    turbine_grid_points\n",
      "        3\n",
      "wake\n",
      "    model_strings\n",
      "        combination_model\n",
      "            sosfs\n",
      "        deflection_model\n",
      "            gauss\n",
      "        turbulence_model\n",
      "            crespo_hernandez\n",
      "        velocity_model\n",
      "            jensen\n",
      "farm\n",
      "    layout_x\n",
      "        [0.0]\n",
      "    layout_y\n",
      "        [0.0]\n",
      "    turbine_type\n",
      "        ['nrel_5MW']\n",
      "    turbine_library_path\n",
      "        /Users/rmudafor/Development/floris/floris/turbine_library\n",
      "flow_field\n",
      "    wind_speeds\n",
      "        [5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0]\n",
      "    wind_directions\n",
      "        [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]\n",
      "    wind_veer\n",
      "        0.0\n",
      "    wind_shear\n",
      "        0.12\n",
      "    air_density\n",
      "        1.225\n",
      "    turbulence_intensities\n",
      "        [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]\n",
      "    reference_wind_height\n",
      "        90.0\n",
      "name\n",
      "    GCH\n",
      "description\n",
      "    Default initialization: Gauss-Curl hybrid model (GCH)\n",
      "floris_version\n",
      "    v4\n"
     ]
    }
   ],
   "source": [
    "import floris\n",
    "\n",
    "# Retrieve the default parameters\n",
    "fdefaults = floris.FlorisModel.get_defaults()\n",
    "\n",
    "# Update wake model parameters\n",
    "fdefaults[\"wake\"][\"model_strings\"][\"velocity_model\"] = \"jensen\"\n",
    "fdefaults[\"wake\"][\"wake_velocity_parameters\"][\"jensen\"][\"we\"] = 0.05\n",
    "\n",
    "# Initialize FLORIS with modified parameters\n",
    "fmodel = floris.FlorisModel(configuration=fdefaults)\n",
    "\n",
    "# Within the calling-code's setup step, update FLORIS as needed\n",
    "fmodel.set(\n",
    "    wind_directions=[i for i in range(10)],\n",
    "    wind_speeds=[5 + i for i in range(10)],\n",
    "    turbulence_intensities=[i for i in range(10)],\n",
    "    # turbine_library_path=\"path/to/turbine_library\",   # Shown here for reference\n",
    "    # turbine_type=[\"my_turbine\"]\n",
    ")\n",
    "\n",
    "# Verify settings are correct\n",
    "fmodel.show_config()  # Shows truncated set of inputs; show all with fmodel.show_config(full=True)\n",
    "\n",
    "# Within the calling code's computation, run FLORIS\n",
    "fmodel.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "floris",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}


================================================
FILE: docs/api_docs.md
================================================
# API Documentation

FLORIS is primarily divided into the {py:mod}`floris` package, which contains the user-level API,
and {py:mod}`floris.core` is the core code that models the wind turbines and wind farms.
Additionally, the {py:mod}`turbine_library` package contains turbine models that ship with FLORIS;
and the {py:mod}`optimization` package contains high-level optimization routines that accept and
work on instantiated `FlorisModel` objects.

```{eval-rst}
.. autosummary::
   :toctree: _autosummary
   :recursive:

   floris.flow_visualization
   floris.floris_model
   floris.wind_data
   floris.uncertain_floris_model
   floris.turbine_library
   floris.parallel_floris_model
   floris.optimization
   floris.layout_visualization
   floris.cut_plane
   floris.core
   floris.convert_turbine_v3_to_v4
   floris.convert_floris_input_v3_to_v4
   floris.utilities
   floris.type_dec
   floris.logging_manager
```


================================================
FILE: docs/architecture.md
================================================

# Architecture and Design

At the outset of the design of the FLORIS software, a few fundamental ideas were identified
that should continue to guide future design decisions. These characteristics should never
be violated, and ongoing work should strive to meet these ideas and expand on them as much
as possible.

- Modularity in wake model formulation:
    - New mathematical formulation should be straightforward to incorporate by non-expert
        software developers.
    - Solver and grid data structures for one wake model should not conflict with the data
        structures for other wake models.
- Any new feature or work should not affect an existing feature:
    - Low level code should be reused as much as possible, but high level code should rarely
        be repurposed.
    - It is expected that a new feature will include a new user entry point
        at the highest level.
    - Avoid flags and if-statements that allow using one high-level routine for multiple unrelated
        tasks.
    - When in doubt, create a new pipeline from the user-level API to the low level implementation
        and refactor to consolidate, if necessary, afterwards.
- Management of abstraction:
    - Low level code is opaque but well tested and exercised; it should be very computationally
        efficient with low algorithmic complexity.
    - High level code should be expressive and clear even if it results in verbose or less
        efficient code.

The FLORIS software consists of two primary high-level packages and a few other low level
packages. The internal structure and hierarchy is described below.

```{mermaid}
classDiagram

    class core["floris.core"] {
        +Core
    }

    class floris["floris"] {
        +FlorisModel
    }

    class logging_manager
    class type_dec
    class utilities

    tools <-- logging_manager
    simulation <-- logging_manager
    simulation <-- type_dec
    simulation <-- utilities
    tools <-- simulation
```

## floris

This is the user interface. Most operations at the user level will happen through `floris`.
This package contains a wide variety of functionality including but not limited to:

- Initializing and driving a simulation with `floris_model`
- Wake field visualization through `flow_visualization`
- Yaw and layout optimization in `optimization`
- Wind data handling in `wind_data`

## floris.core

This is the core simulation package. This should primarily be used within `floris.core` and
`floris`, and user scripts generally won't interact directly with this package.

```{mermaid}
classDiagram

    class Core

    class Farm

    class FlowField {
        u: NDArrayFloat
        v: NDArrayFloat
        w: NDArrayFloat
    }

    class Grid {
        <<interface>>
        x: NDArrayFloat
        y: NDArrayFloat
        z: NDArrayFloat
    }
    class TurbineGrid
    class TurbineCubatureGrid
    class FlowFieldPlanarGrid
    class PointsGrid

    class WakeModelManager {
        <<interface>>
    }
    class WakeCombination {
        parameters: dict
        function()
    }
    class WakeDeflection {
        parameters: dict
        function()
    }
    class WakeTurbulence {
        parameters: dict
        function()
    }
    class WakeVelocity {
        parameters: dict
        function()
    }

    class Solver {
        <<interface>>
        parameters: dict
    }

    Core *-- Farm
    Core *-- FlowField
    Core *-- Grid
    Core *-- WakeModelManager
    Core --> Solver
    WakeModelManager *-- WakeCombination
    WakeModelManager *-- WakeDeflection
    WakeModelManager *-- WakeTurbulence
    WakeModelManager *-- WakeVelocity

    Grid <|-- TurbineGrid
    Grid <|-- TurbineCubatureGrid
    Grid <|-- FlowFieldPlanarGrid
    Grid <|-- PointsGrid

    Solver --> Farm
    Solver --> FlowField
    Solver --> Grid
    Solver --> WakeModelManager
```


================================================
FILE: docs/bibliography.md
================================================

# Bibliography

```{bibliography}
:style: unsrt
```


================================================
FILE: docs/code_quality.ipynb
================================================
{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Code Quality\n",
    "\n",
    "This page contains information on various code quality metrics\n",
    "that are collected during the development cycle. Some of these\n",
    "are autogenerated while others rely on manual scripts and updating\n",
    "the documentation, so these will be updating as needed and when\n",
    "appropriate. All plots show the corresponding commit hash\n",
    "when hovering over a point with the mouse pointer."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Live Code Quality Metrics\n",
    "\n",
    "Live code quality metrics are computed when develop branch is updated.  [Live Chart](https://nrel.github.io/floris/dev/bench/).  Note these charts are computed within github actions and are somewhat noisy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Performance History\n",
    "\n",
    "The plot below shows the runtime performance over a series of commits for a\n",
    "3-turbine test case with 1,440 atmospheric conditions.\n",
    "This data is collected on [NLR's Kestrel supercomputer](https://nrel.github.io/HPC/Documentation/Systems/Kestrel/)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "tags": [
     "hide-cell"
    ]
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/var/folders/yp/vdv3q8mn4xj1_m277lk54s75tvdqcf/T/ipykernel_74430/1348870237.py:3: DeprecationWarning: \n",
      "Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\n",
      "(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\n",
      "but was not found to be installed on your system.\n",
      "If this would cause problems for you,\n",
      "please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\n",
      "        \n",
      "  import pandas as pd\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "    <style>\n",
       "        .bk-notebook-logo {\n",
       "            display: block;\n",
       "            width: 20px;\n",
       "            height: 20px;\n",
       "            background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAOkSURBVDiNjZRtaJVlGMd/1/08zzln5zjP1LWcU9N0NkN8m2CYjpgQYQXqSs0I84OLIC0hkEKoPtiH3gmKoiJDU7QpLgoLjLIQCpEsNJ1vqUOdO7ppbuec5+V+rj4ctwzd8IIbbi6u+8f1539dt3A78eXC7QizUF7gyV1fD1Yqg4JWz84yffhm0qkFqBogB9rM8tZdtwVsPUhWhGcFJngGeWrPzHm5oaMmkfEg1usvLFyc8jLRqDOMru7AyC8saQr7GG7f5fvDeH7Ej8CM66nIF+8yngt6HWaKh7k49Soy9nXurCi1o3qUbS3zWfrYeQDTB/Qj6kX6Ybhw4B+bOYoLKCC9H3Nu/leUTZ1JdRWkkn2ldcCamzrcf47KKXdAJllSlxAOkRgyHsGC/zRday5Qld9DyoM4/q/rUoy/CXh3jzOu3bHUVZeU+DEn8FInkPBFlu3+nW3Nw0mk6vCDiWg8CeJaxEwuHS3+z5RgY+YBR6V1Z1nxSOfoaPa4LASWxxdNp+VWTk7+4vzaou8v8PN+xo+KY2xsw6une2frhw05CTYOmQvsEhjhWjn0bmXPjpE1+kplmmkP3suftwTubK9Vq22qKmrBhpY4jvd5afdRA3wGjFAgcnTK2s4hY0/GPNIb0nErGMCRxWOOX64Z8RAC4oCXdklmEvcL8o0BfkNK4lUg9HTl+oPlQxdNo3Mg4Nv175e/1LDGzZen30MEjRUtmXSfiTVu1kK8W4txyV6BMKlbgk3lMwYCiusNy9fVfvvwMxv8Ynl6vxoByANLTWplvuj/nF9m2+PDtt1eiHPBr1oIfhCChQMBw6Aw0UulqTKZdfVvfG7VcfIqLG9bcldL/+pdWTLxLUy8Qq38heUIjh4XlzZxzQm19lLFlr8vdQ97rjZVOLf8nclzckbcD4wxXMidpX30sFd37Fv/GtwwhzhxGVAprjbg0gCAEeIgwCZyTV2Z1REEW8O4py0wsjeloKoMr6iCY6dP92H6Vw/oTyICIthibxjm/DfN9lVz8IqtqKYLUXfoKVMVQVVJOElGjrnnUt9T9wbgp8AyYKaGlqingHZU/uG2NTZSVqwHQTWkx9hxjkpWDaCg6Ckj5qebgBVbT3V3NNXMSiWSDdGV3hrtzla7J+duwPOToIg42ChPQOQjspnSlp1V+Gjdged7+8UN5CRAV7a5EdFNwCjEaBR27b3W890TE7g24NAP/mMDXRWrGoFPQI9ls/MWO2dWFAar/xcOIImbbpA3zgAAAABJRU5ErkJggg==);\n",
       "        }\n",
       "    </style>\n",
       "    <div>\n",
       "        <a href=\"https://bokeh.org\" target=\"_blank\" class=\"bk-notebook-logo\"></a>\n",
       "        <span id=\"a67e122f-6aa9-4ff8-97f7-6378dc8e5a11\">Loading BokehJS ...</span>\n",
       "    </div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": "'use strict';\n(function(root) {\n  function now() {\n    return new Date();\n  }\n\n  const force = true;\n\n  if (typeof root._bokeh_onload_callbacks === \"undefined\" || force === true) {\n    root._bokeh_onload_callbacks = [];\n    root._bokeh_is_loading = undefined;\n  }\n\nconst JS_MIME_TYPE = 'application/javascript';\n  const HTML_MIME_TYPE = 'text/html';\n  const EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n  const CLASS_NAME = 'output_bokeh rendered_html';\n\n  /**\n   * Render data to the DOM node\n   */\n  function render(props, node) {\n    const script = document.createElement(\"script\");\n    node.appendChild(script);\n  }\n\n  /**\n   * Handle when an output is cleared or removed\n   */\n  function handleClearOutput(event, handle) {\n    function drop(id) {\n      const view = Bokeh.index.get_by_id(id)\n      if (view != null) {\n        view.model.document.clear()\n        Bokeh.index.delete(view)\n      }\n    }\n\n    const cell = handle.cell;\n\n    const id = cell.output_area._bokeh_element_id;\n    const server_id = cell.output_area._bokeh_server_id;\n\n    // Clean up Bokeh references\n    if (id != null) {\n      drop(id)\n    }\n\n    if (server_id !== undefined) {\n      // Clean up Bokeh references\n      const cmd_clean = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n      cell.notebook.kernel.execute(cmd_clean, {\n        iopub: {\n          output: function(msg) {\n            const id = msg.content.text.trim()\n            drop(id)\n          }\n        }\n      });\n      // Destroy server and session\n      const cmd_destroy = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n      cell.notebook.kernel.execute(cmd_destroy);\n    }\n  }\n\n  /**\n   * Handle when a new output is added\n   */\n  function handleAddOutput(event, handle) {\n    const output_area = handle.output_area;\n    const output = handle.output;\n\n    // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n    if ((output.output_type != \"display_data\") || (!Object.prototype.hasOwnProperty.call(output.data, EXEC_MIME_TYPE))) {\n      return\n    }\n\n    const toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n\n    if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n      toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n      // store reference to embed id on output_area\n      output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n    }\n    if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n      const bk_div = document.createElement(\"div\");\n      bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n      const script_attrs = bk_div.children[0].attributes;\n      for (let i = 0; i < script_attrs.length; i++) {\n        toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n        toinsert[toinsert.length - 1].firstChild.textContent = bk_div.children[0].textContent\n      }\n      // store reference to server id on output_area\n      output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n    }\n  }\n\n  function register_renderer(events, OutputArea) {\n\n    function append_mime(data, metadata, element) {\n      // create a DOM node to render to\n      const toinsert = this.create_output_subarea(\n        metadata,\n        CLASS_NAME,\n        EXEC_MIME_TYPE\n      );\n      this.keyboard_manager.register_events(toinsert);\n      // Render to node\n      const props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n      render(props, toinsert[toinsert.length - 1]);\n      element.append(toinsert);\n      return toinsert\n    }\n\n    /* Handle when an output is cleared or removed */\n    events.on('clear_output.CodeCell', handleClearOutput);\n    events.on('delete.Cell', handleClearOutput);\n\n    /* Handle when a new output is added */\n    events.on('output_added.OutputArea', handleAddOutput);\n\n    /**\n     * Register the mime type and append_mime function with output_area\n     */\n    OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n      /* Is output safe? */\n      safe: true,\n      /* Index of renderer in `output_area.display_order` */\n      index: 0\n    });\n  }\n\n  // register the mime type if in Jupyter Notebook environment and previously unregistered\n  if (root.Jupyter !== undefined) {\n    const events = require('base/js/events');\n    const OutputArea = require('notebook/js/outputarea').OutputArea;\n\n    if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n      register_renderer(events, OutputArea);\n    }\n  }\n  if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n    root._bokeh_timeout = Date.now() + 5000;\n    root._bokeh_failed_load = false;\n  }\n\n  const NB_LOAD_WARNING = {'data': {'text/html':\n     \"<div style='background-color: #fdd'>\\n\"+\n     \"<p>\\n\"+\n     \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n     \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n     \"</p>\\n\"+\n     \"<ul>\\n\"+\n     \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n     \"<li>use INLINE resources instead, as so:</li>\\n\"+\n     \"</ul>\\n\"+\n     \"<code>\\n\"+\n     \"from bokeh.resources import INLINE\\n\"+\n     \"output_notebook(resources=INLINE)\\n\"+\n     \"</code>\\n\"+\n     \"</div>\"}};\n\n  function display_loaded(error = null) {\n    const el = document.getElementById(\"a67e122f-6aa9-4ff8-97f7-6378dc8e5a11\");\n    if (el != null) {\n      const html = (() => {\n        if (typeof root.Bokeh === \"undefined\") {\n          if (error == null) {\n            return \"BokehJS is loading ...\";\n          } else {\n            return \"BokehJS failed to load.\";\n          }\n        } else {\n          const prefix = `BokehJS ${root.Bokeh.version}`;\n          if (error == null) {\n            return `${prefix} successfully loaded.`;\n          } else {\n            return `${prefix} <b>encountered errors</b> while loading and may not function as expected.`;\n          }\n        }\n      })();\n      el.innerHTML = html;\n\n      if (error != null) {\n        const wrapper = document.createElement(\"div\");\n        wrapper.style.overflow = \"auto\";\n        wrapper.style.height = \"5em\";\n        wrapper.style.resize = \"vertical\";\n        const content = document.createElement(\"div\");\n        content.style.fontFamily = \"monospace\";\n        content.style.whiteSpace = \"pre-wrap\";\n        content.style.backgroundColor = \"rgb(255, 221, 221)\";\n        content.textContent = error.stack ?? error.toString();\n        wrapper.append(content);\n        el.append(wrapper);\n      }\n    } else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(() => display_loaded(error), 100);\n    }\n  }\n\n  function run_callbacks() {\n    try {\n      root._bokeh_onload_callbacks.forEach(function(callback) {\n        if (callback != null)\n          callback();\n      });\n    } finally {\n      delete root._bokeh_onload_callbacks\n    }\n    console.debug(\"Bokeh: all callbacks have finished\");\n  }\n\n  function load_libs(css_urls, js_urls, callback) {\n    if (css_urls == null) css_urls = [];\n    if (js_urls == null) js_urls = [];\n\n    root._bokeh_onload_callbacks.push(callback);\n    if (root._bokeh_is_loading > 0) {\n      console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n      return null;\n    }\n    if (js_urls == null || js_urls.length === 0) {\n      run_callbacks();\n      return null;\n    }\n    console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n    root._bokeh_is_loading = css_urls.length + js_urls.length;\n\n    function on_load() {\n      root._bokeh_is_loading--;\n      if (root._bokeh_is_loading === 0) {\n        console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n        run_callbacks()\n      }\n    }\n\n    function on_error(url) {\n      console.error(\"failed to load \" + url);\n    }\n\n    for (let i = 0; i < css_urls.length; i++) {\n      const url = css_urls[i];\n      const element = document.createElement(\"link\");\n      element.onload = on_load;\n      element.onerror = on_error.bind(null, url);\n      element.rel = \"stylesheet\";\n      element.type = \"text/css\";\n      element.href = url;\n      console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n      document.body.appendChild(element);\n    }\n\n    for (let i = 0; i < js_urls.length; i++) {\n      const url = js_urls[i];\n      const element = document.createElement('script');\n      element.onload = on_load;\n      element.onerror = on_error.bind(null, url);\n      element.async = false;\n      element.src = url;\n      console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n      document.head.appendChild(element);\n    }\n  };\n\n  function inject_raw_css(css) {\n    const element = document.createElement(\"style\");\n    element.appendChild(document.createTextNode(css));\n    document.body.appendChild(element);\n  }\n\n  const js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.6.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.6.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.6.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.6.3.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.6.3.min.js\"];\n  const css_urls = [];\n\n  const inline_js = [    function(Bokeh) {\n      Bokeh.set_log_level(\"info\");\n    },\nfunction(Bokeh) {\n    }\n  ];\n\n  function run_inline_js() {\n    if (root.Bokeh !== undefined || force === true) {\n      try {\n            for (let i = 0; i < inline_js.length; i++) {\n      inline_js[i].call(root, root.Bokeh);\n    }\n\n      } catch (error) {display_loaded(error);throw error;\n      }if (force === true) {\n        display_loaded();\n      }} else if (Date.now() < root._bokeh_timeout) {\n      setTimeout(run_inline_js, 100);\n    } else if (!root._bokeh_failed_load) {\n      console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n      root._bokeh_failed_load = true;\n    } else if (force !== true) {\n      const cell = $(document.getElementById(\"a67e122f-6aa9-4ff8-97f7-6378dc8e5a11\")).parents('.cell').data().cell;\n      cell.output_area.append_execute_result(NB_LOAD_WARNING)\n    }\n  }\n\n  if (root._bokeh_is_loading === 0) {\n    console.debug(\"Bokeh: BokehJS loaded, going straight to plotting\");\n    run_inline_js();\n  } else {\n    load_libs(css_urls, js_urls, function() {\n      console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n      run_inline_js();\n    });\n  }\n}(window));",
      "application/vnd.bokehjs_load.v0+json": ""
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from bokeh.plotting import figure, show, output_notebook\n",
    "from bokeh.models import ColumnDataSource, HoverTool, Range1d\n",
    "import pandas as pd\n",
    "from datetime import datetime\n",
    "\n",
    "output_notebook()\n",
    "\n",
    "COLORS = ['blue', 'green', 'red', 'cyan', 'magenta', 'y', 'k']\n",
    "\n",
    "columns = [\"commit_hash\", \"commit_hash_8char\", \"date\", \"jensen\", \"gauss\", \"gch\", \"cc\", \"emgauss\", \"tooltip_label\"]\n",
    "data = [\n",
    "    (\"df25a9cfacd3d652361d2bd37f568af00acb2631\", \"df25a9cf\", datetime(2021, 12, 29), 1.2691, 1.2584, 1.6432,   None,   None, \"df25a9cf\"),\n",
    "    (\"b797390a43298a815f3ff57955cfdc71ecf3e866\", \"b797390a\", datetime(2022,  1,  3), 0.6867, 1.2354, 1.8026,   None,   None, \"b797390a\"),\n",
    "    (\"01a02d5f91b2f4a863eebe88a618974b0749d1c4\", \"01a02d5f\", datetime(2022,  1,  4), 0.2329, 0.5661, 0.9869,   None,   None, \"01a02d5f\"),\n",
    "    (\"dd847210082035d43b0273ae63a76a53cb8d2e12\", \"dd847210\", datetime(2022,  1,  6), 0.2290, 0.5815, 0.9822,   None,   None, \"dd847210\"),\n",
    "    (\"33779269e98cc882a5f066c462d8ec1eadf37a1a\", \"33779269\", datetime(2022,  1, 10), 0.2300, 0.5845, 1.0114,   None,   None, \"33779269\"),\n",
    "    (\"12890e029a7155b074b9b325d320d1798338e287\", \"12890e02\", datetime(2022,  1, 11), 0.2296, 0.5660, 1.0114,   None,   None, \"12890e02\"),\n",
    "    (\"66dafc08bd620d96deda7d526b0e4bfc3b086650\", \"66dafc08\", datetime(2022,  1, 12), 0.2342, 0.5937, 1.0284,   None,   None, \"66dafc08\"),\n",
    "    (\"a325819b3b03b84bd76ad455e3f9b4600744ba14\", \"a325819b\", datetime(2022,  1, 13), 0.2349, 0.5711, 1.0072,   None,   None, \"a325819b\"),\n",
    "    (\"8a2c1a610295c007f0222ce737723c341189811d\", \"8a2c1a61\", datetime(2022,  1, 14), 0.2338, 0.5837, 1.0242,   None,   None, \"8a2c1a61\"),\n",
    "    (\"c6bc79b0cfbc8ce5d6da0d33b68028157d2e93c0\", \"c6bc79b0\", datetime(2022,  1, 14), 0.2374, 0.5653, 0.9781,   None,   None, \"c6bc79b0\"),\n",
    "    (\"03e1f461c152e4f221fe92c834f2787680cf5772\", \"03e1f461\", datetime(2022,  1, 18), 0.2423, 0.5820, 1.0411, 1.2251,   None, \"PR #56\"),\n",
    "    (\"9e96d6c412b64fe76a57e7de8af3b00c21d18348\", \"9e96d6c4\", datetime(2022,  1, 19), 0.2507, 0.5674, 1.0053, 1.1828,   None, \"v3.0rc1\"),\n",
    "    (\"2a98428f9c6fb9bb4302ae09809441bf3e7162b0\", \"2a98428f\", datetime(2022,  2, 15), 0.1662, 0.5699, 1.0081, 1.1906,   None, \"PR #317\"),\n",
    "    (\"9b4e85cf1b41ba7001aaba1a830b93e176f3dd43\", \"9b4e85cf\", datetime(2022,  3,  1), 0.1710, 0.6143, 1.0626, 1.2013,   None, \"v3.0\"),\n",
    "    (\"d18f4d263ecabf502242592f9d60815a07c7b89c\", \"d18f4d26\", datetime(2022,  3,  4), 0.1766, 0.6020, 1.0612, 1.2088,   None, \"v3.0.1\"),\n",
    "    (\"a23241bb9e45078e36a4662d48c9d3fe0c3316e4\", \"a23241bb\", datetime(2022,  4,  6), 0.1764, 0.6044, 1.0656, 1.2067,   None, \"v3.1\"),\n",
    "    (\"c2006b0011a5df036c306c15e75763ec492dafda\", \"c2006b00\", datetime(2022,  6, 22), 0.1801, 0.6082, 1.0603, 1.2025,   None, \"v3.1.1\"),\n",
    "    (\"0c2adf3e702b6427da946a6ba9dbedbea22738be\", \"0c2adf3e\", datetime(2022,  9, 16), 0.1753, 0.6202, 1.0486, 1.1962,   None, \"v3.2\"),\n",
    "    (\"39c466000b1874e06a6f58da9c30bb877fc8d4d2\", \"39c46600\", datetime(2022, 11, 20), 0.1738, 0.6140, 1.0498, 1.1783,   None, \"v3.2.1\"),\n",
    "    (\"8436fd78b002e5792f5d0dd1409332d171036d49\", \"8436fd78\", datetime(2023,  2,  8), 0.1980, 0.6334, 1.0631, 1.2009,   None, \"v3.2.2\"),\n",
    "    (\"07a45b66c5facfea06c40bd82e34040c97560640\", \"07a45b66\", datetime(2023,  2,  8), 0.1831, 0.6070, 1.0233, 1.1991,   None, \"07a45b66\"),\n",
    "    (\"1d84538c334a502c6ad7df48b8cc2309d6a6436d\", \"1d84538c\", datetime(2023,  2, 22), 0.1771, 0.6226, 1.0541, 1.2044,   None, \"1d84538c\"),\n",
    "    (\"4d528a3d6456621a382d409b5145a877b5414b88\", \"4d528a3d\", datetime(2023,  2, 23), 0.1768, 0.6026, 1.0366, 1.1958,   None, \"4d528a3d\"),\n",
    "    (\"8c637b36b66069b216cb94ae87d4c0a91e9b211e\", \"8c637b36\", datetime(2023,  2, 27), 0.2052, 0.6264, 1.0655, 1.2137,   None, \"8c637b36\"),\n",
    "    (\"4d23fa6dd78d0497deb4fd62783f0b3ee4204579\", \"4d23fa6d\", datetime(2023,  2, 27), 0.1996, 0.6083, 1.0465, 1.2184,   None, \"4d23fa6d\"),\n",
    "    (\"015f6874c320efee2c0d1ae76eea4a5b043d69d6\", \"015f6874\", datetime(2023,  3,  1), 0.2204, 0.6383, 1.0633, 1.2093,   None, \"015f6874\"),\n",
    "    (\"26f06d449da208ce64724b1463b07ad20746cbdc\", \"26f06d44\", datetime(2023,  3,  6), 0.1848, 0.6186, 1.0410, 1.2076,   None, \"26f06d44\"),\n",
    "    (\"6b9d6bb8bec6e3ea548f5858e2a8ea5986264fc8\", \"6b9d6bb8\", datetime(2023,  3,  6), 0.1946, 0.6247, 1.0742, 1.2250,   None, \"6b9d6bb8\"),\n",
    "    (\"b796bd0fd92ba6b91d590f6cb60bb7ab3bca9932\", \"b796bd0f\", datetime(2023,  3,  6), 0.2027, 0.6333, 1.0612, 1.2038,   None, \"b796bd0f\"),\n",
    "    (\"780aef7c7b4b9cafea3e323d536a34a4af5818b4\", \"780aef7c\", datetime(2023,  3,  7), 0.1922, 0.6292, 1.0494, 1.2125,   None, \"780aef7c\"),\n",
    "    (\"9f93ad9bf85e4a0e6baf5b62ea4b3ef143729861\", \"9f93ad9b\", datetime(2023,  3,  7), 0.2007, 0.6342, 1.0611, 1.2059,   None, \"9f93ad9b\"),\n",
    "    (\"16628a0ba45a675df762245694e0a7666a3478f8\", \"16628a0b\", datetime(2023,  3,  7), 0.2110, 0.6405, 1.0799, 1.2101,   None, \"v3.3\"),\n",
    "    (\"01684c8559604344bd09791268131819a09770a8\", \"01684c85\", datetime(2023,  3, 17), 0.2067, 0.6334, 1.0691, 1.1924,   None, \"01684c85\"),\n",
    "    (\"e9231fb893c765b723fa4c1e087a58761b6aa471\", \"e9231fb8\", datetime(2023,  3, 20), 0.2082, 0.6357, 1.0728, 1.2212,   None, \"e9231fb8\"),\n",
    "    (\"219889e243ffc69c71b6f7747f5af751d5694de1\", \"219889e2\", datetime(2023,  3, 23), 0.1912, 0.6182, 1.0651, 1.2033,   None, \"219889e2\"),\n",
    "    (\"6124d2a82a7a823722210bc2e8516d355ba19eb3\", \"6124d2a8\", datetime(2023,  4,  5), 0.2064, 0.6419, 1.0711, 1.1933,   None, \"6124d2a8\"),\n",
    "    (\"f6e4287f712cc866893e71b1ea7a7546e4567bf9\", \"f6e4287f\", datetime(2023,  4, 25), 0.1944, 0.6103, 1.0460, 1.2236,   None, \"f6e4287f\"),\n",
    "    (\"f2797fef396f2f19b02abb1f9555b678dac614f1\", \"f2797fef\", datetime(2023,  4, 25), 0.1997, 0.6357, 1.0648, 1.2128,   None, \"f2797fef\"),\n",
    "    (\"b4e538f530048fec58eaca5170be82c67dbdcceb\", \"b4e538f5\", datetime(2023,  4, 25), 0.2103, 0.6415, 1.0679, 1.2248,   None, \"b4e538f5\"),\n",
    "    (\"68820b715ed6b2c981aa11d29c0102e879280d79\", \"68820b71\", datetime(2023,  4, 25), 0.2076, 0.6354, 1.0625, 1.2018,   None, \"68820b71\"),\n",
    "    (\"03deffeda91fa8d8ab188d57b9fa302a7be008e0\", \"03deffed\", datetime(2023,  4, 25), 0.2138, 0.6453, 1.0738, 1.2148,   None, \"03deffed\"),\n",
    "    (\"0d2bfecc271d561f67050659684b4797af8ee740\", \"0d2bfecc\", datetime(2023,  4, 25), 0.2117, 0.6464, 1.0855, 1.2213,   None, \"0d2bfecc\"),\n",
    "    (\"1d03a465593f56c99a64a576d185d4ed17b659f2\", \"1d03a465\", datetime(2023,  4, 25), 0.2060, 0.6376, 1.0722, 1.2129,   None, \"1d03a465\"),\n",
    "    (\"78a953b7ef9a36b62e5b446c80ed68abfddbfb74\", \"78a953b7\", datetime(2023,  5,  4), 0.2170, 0.6323, 1.0673, 1.2116,   None, \"78a953b7\"),\n",
    "    (\"6c4f70ffbf3d4d2922d41d0032ae1b93d8a23c99\", \"6c4f70ff\", datetime(2023,  5,  4), 0.2123, 0.6407, 1.0688, 1.2183,   None, \"6c4f70ff\"),\n",
    "    (\"ab03282623d0262b20b8c132efcdcace2dace766\", \"ab032826\", datetime(2023,  5,  6), 0.1846, 0.6147, 1.0605, 1.2106,   None, \"ab032826\"),\n",
    "    (\"d2f7a45af27a6b40027d6f6a0f4f0be0c6dee5d9\", \"d2f7a45a\", datetime(2023,  5,  6), 0.1924, 0.6259, 1.0525, 1.1896,   None, \"d2f7a45a\"),\n",
    "    (\"98b23f3d517481b127f190f5f8b7ebfae7f8b6b2\", \"98b23f3d\", datetime(2023,  5,  6), 0.1940, 0.6177, 1.0524, 1.1916,   None, \"98b23f3d\"),\n",
    "    (\"452425de723cc1640d999022389672caf9bffbd0\", \"452425de\", datetime(2023,  5,  6), 0.2075, 0.6297, 1.0647, 1.2017,   None, \"452425de\"),\n",
    "    (\"85dadb1a566c9fa8dc84cb9837b98bd5d23b8d58\", \"85dadb1a\", datetime(2023,  5,  7), 0.1853, 0.6164, 1.0244, 1.1917,   None, \"85dadb1a\"),\n",
    "    (\"432ee7f96c1f6cccd05a0034c86c720cdb63a3e6\", \"432ee7f9\", datetime(2023,  5, 10), 0.1813, 0.6003, 1.0310, 1.1856,   None, \"432ee7f9\"),\n",
    "    (\"ebd70ecaef14c0e239337eb6e36506303378a31a\", \"ebd70eca\", datetime(2023,  5, 10), 0.1814, 0.6012, 1.0402, 1.2075, 0.3262, \"ebd70eca\"),\n",
    "    (\"77fa7155d55bdf3fd43e29f58fe57feffcb107cf\", \"77fa7155\", datetime(2023,  5, 11), 0.1763, 0.6095, 1.0507, 1.2181, 0.3431, \"77fa7155\"),\n",
    "    (\"d5d4b1346bd6acba9ba41b4bf546640de162a9d6\", \"d5d4b134\", datetime(2023,  5, 12), 0.1921, 0.6277, 1.0608, 1.2104, 0.3342, \"d5d4b134\"),\n",
    "    (\"d5d4b1346bd6acba9ba41b4bf546640de162a9d6\", \"d5d4b134\", datetime(2023,  5, 16), 0.1783, 0.6172, 1.0474, 1.1958, 0.3263, \"d5d4b134\"),\n",
    "    (\"7c879f1ce18b52d9b0a8eecf877d03e66afc975b\", \"7c879f1c\", datetime(2023,  5, 16), 0.1754, 0.5924, 1.0241, 1.1966, 0.3096, \"7c879f1c\"),\n",
    "    (\"2aa9f2a55686f2ee5dc407e8e0223eb25176d906\", \"2aa9f2a5\", datetime(2023,  5, 16), 0.1843, 0.6066, 1.0405, 1.1988, 0.3263, \"2aa9f2a5\"),\n",
    "    (\"5e5bb7f4e653621e7a81ff4bcaa27dbc1f759de7\", \"5e5bb7f4\", datetime(2023,  5, 16), 0.1911, 0.6197, 1.0425, 1.1792, 0.3426, \"v3.4\"),\n",
    "    (\"d91953a499dfb88b457a1e7a07903debbda4058b\", \"d91953a4\", datetime(2023,  6,  1), 0.1839, 0.6171, 1.0521, 1.1919, 0.3269, \"d91953a4\"),\n",
    "    (\"76742879c81c9baced49b9fc60abbf1d2eba65ff\", \"76742879\", datetime(2023,  7,  3), 0.1818, 0.6128, 1.0514, 1.1965, 0.3338, \"76742879\"),\n",
    "    (\"9c73a41eaca95bb718ac79980a1799dfa1c48cf3\", \"9c73a41e\", datetime(2023,  7,  6), 0.1795, 0.6011, 1.0335, 1.2146, 0.3142, \"9c73a41e\"),\n",
    "    (\"67104dd714de939be136646af68edd9643ddfcd3\", \"67104dd7\", datetime(2023,  7,  6), 0.1869, 0.5838, 0.7982, 0.9479, 0.3153, \"67104dd7\"),\n",
    "    (\"e6906feebdee6bdd2103f0bd390679e6a1b0052d\", \"e6906fee\", datetime(2023,  7,  7), 0.1751, 0.5780, 0.7820, 0.9452, 0.3136, \"e6906fee\"),\n",
    "    (\"8908ab47eaa8a3d7e7c9126484b524f751e41f55\", \"8908ab47\", datetime(2023,  7, 10), 0.1739, 0.5472, 0.7007, 0.8955, 0.3012, \"8908ab47\"),\n",
    "    (\"063d8b58464f95520c9887ac4f575e6c1f6880d8\", \"063d8b58\", datetime(2023,  7, 11), 0.1758, 0.5891, 0.7337, 0.8818, 0.3062, \"063d8b58\"),\n",
    "    (\"59e53a66aef134a3c9e912f9468ca667b599d4e5\", \"59e53a66\", datetime(2023,  7, 27), 0.1918, 0.6174, 1.0461, 1.1964, 0.3380, \"59e53a66\"),\n",
    "    (\"cd14608474be8561c188d2aa7a772b8ac753fb70\", \"cd146084\", datetime(2023,  8,  3), 0.1799, 0.5783, 0.7979, 0.9539, 0.3214, \"cd146084\"),\n",
    "    (\"db958c4b779ffc825689e052958020864cbcde63\", \"db958c4b\", datetime(2023,  8, 15), 0.1683, 0.5486, 0.7048, 0.8803, 0.2955, \"db958c4b\"),\n",
    "    (\"8ece0f5f7d3bfd66f4f83198debf5627344af534\", \"8ece0f5f\", datetime(2023,  8, 15), 0.1697, 0.5529, 0.7032, 0.8925, 0.2899, \"8ece0f5f\"),\n",
    "    (\"77ea50d9bd5d01f7110dbebf1ba689a25eee9d96\", \"77ea50d9\", datetime(2023,  9, 11), 0.1858, 0.5741, 0.7973, 0.9559, 0.3191, \"77ea50d9\"),\n",
    "    (\"05b900c228d427bfa8e531527b546cdeb822cfc9\", \"05b900c2\", datetime(2023, 10,  4), 0.1842, 0.5622, 0.7196, 0.8759, 0.2821, \"05b900c2\"),\n",
    "    (\"2dccbbd0ca67a274a2aeb9996f262014b3137fc0\", \"2dccbbd0\", datetime(2023, 10, 20), 0.1708, 0.5382, 0.6906, 0.8738, 0.2908, \"2dccbbd0\"),\n",
    "    (\"e9c90aa521917e587dd9497d529822f359eec3e2\", \"e9c90aa5\", datetime(2023, 10, 26), 0.1778, 0.5911, 0.7423, 0.8710, 0.2858, \"e9c90aa5\"),\n",
    "    (\"6c3ddb48b59d286899a8efd5989d741f86c4ade3\", \"6c3ddb48\", datetime(2023, 10, 26), 0.1700, 0.5585, 0.6991, 0.8823, 0.2887, \"6c3ddb48\"),\n",
    "    (\"31fe1b69ff863f0a610aec5b22424382ec3cc933\", \"31fe1b69\", datetime(2023, 10, 26), 0.1661, 0.5548, 0.7630, 0.9317, 0.2969, \"v3.5\"),\n",
    "    (\"a4768d08e172e009efb7ccafb8dc37a90753df7f\", \"a4768d08\", datetime(2023, 11,  8), 0.1725, 0.5768, 0.7635, 0.8827, 0.2990, \"a4768d08\"),\n",
    "    (\"1a2e86847d7942d9ecac20d91d2f4cd73685b230\", \"1a2e8684\", datetime(2023, 11, 15), 0.1764, 0.5933, 0.7970, 0.8984, 0.2972, \"1a2e8684\"),\n",
    "    (\"bc4fd2812636baba036d6f5648c6e77bcfb263e4\", \"bc4fd281\", datetime(2023, 11, 15), 0.1728, 0.5468, 0.7200, 0.8730, 0.2886, \"bc4fd281\"),\n",
    "    (\"34a7e0cd84226520f5a39cf3345699f012aad505\", \"34a7e0cd\", datetime(2023, 11, 28), 0.1697, 0.5541, 0.7179, 0.8844, 0.2929, \"34a7e0cd\"),\n",
    "    (\"e1dd6b73ae1d9552e0fe9679c0d35199c113d647\", \"e1dd6b73\", datetime(2023, 11, 30), 0.1715, 0.5709, 0.7846, 0.9334, 0.2871, \"e1dd6b73\"),\n",
    "    (\"599f2266ad55f73f4afaf80d4d1e32523a256d3b\", \"599f2266\", datetime(2023, 12,  1), 0.1892, 0.5930, 0.7877, 0.9125, 0.2928, \"599f2266\"),\n",
    "    (\"52b8a5f595f565b149a227b26bea7786d742f15c\", \"52b8a5f5\", datetime(2023, 12,  6), 0.1747, 0.5856, 0.7290, 0.8946, 0.2960, \"52b8a5f5\"),\n",
    "    (\"6f2256dab34c9d9548bd6d4d81594605d75434bd\", \"6f2256da\", datetime(2023, 12,  6), 0.1799, 0.5777, 0.7798, 0.9518, 0.3016, \"6f2256da\"),\n",
    "    (\"b6de318f12c93872daec8762edecb66d311504b5\", \"b6de318f\", datetime(2023, 12,  6), 0.1820, 0.5993, 0.8048, 0.9650, 0.3211, \"b6de318f\"),\n",
    "    (\"94357caf7092f6bfb6d8b51b9daf1ae9b47f26dc\", \"94357caf\", datetime(2023, 12,  7), 0.1731, 0.5623, 0.7093, 0.8866, 0.2924, \"94357caf\"),\n",
    "    (\"64ae6789f1860734ab4d6d34cd7c4313a85274fc\", \"64ae6789\", datetime(2023, 12,  8), 0.1701, 0.5625, 0.7113, 0.8901, 0.2897, \"64ae6789\"),\n",
    "    (\"da61128340ac0e520b4583eb759bf771512332f6\", \"da611283\", datetime(2023, 12, 13), 0.1713, 0.5603, 0.6923, 0.8770, 0.2882, \"da611283\"),\n",
    "    (\"bbcb8c33f4f35036c8156c57cea60fea5c5e17af\", \"bbcb8c33\", datetime(2023, 12, 13), 0.1748, 0.5769, 0.6966, 0.8766, 0.2840, \"bbcb8c33\"),\n",
    "    (\"ebdf9a146359606dc5e13363beee6dd82ad1c247\", \"ebdf9a14\", datetime(2023, 12, 13), 0.1782, 0.5622, 0.7108, 0.8755, 0.2895, \"ebdf9a14\"),\n",
    "    (\"b88dc7bb15370da91956ca24db3875245dc073d2\", \"b88dc7bb\", datetime(2024,  1,  4), 0.1836, 0.5699, 0.7204, 0.8891, 0.2957, \"b88dc7bb\"),\n",
    "    (\"a88a15432ef01f7600e3ccd7b9d2b4ba89a01df0\", \"a88a1543\", datetime(2024,  2,  7), 0.1922, 0.5925, 0.7759, 0.8914, 0.2937, \"a88a1543\"),\n",
    "    (\"c7f8f36178f35ccd8e08e0ce10a77fc487f78a14\", \"c7f8f361\", datetime(2024,  2, 20), 0.1801, 0.5775, 0.7097, 0.8755, 0.2907, \"c7f8f361\"),\n",
    "    (\"4b331398bc4a08edcd32539157cff2866f481875\", \"4b331398\", datetime(2024,  3, 19), 0.1810, 0.5678, 0.7276, 0.8805, 0.2958, \"4b331398\"),\n",
    "    (\"faba9890d5d07d9d8720464547602df1ff73124b\", \"faba9890\", datetime(2024,  3, 26), 0.1839, 0.5771, 0.7172, 0.8974, 0.2981, \"faba9890\"),\n",
    "    (\"3fba47f290480d1795f2d9f813179bc61844778b\", \"3fba47f2\", datetime(2024,  4,  5), 0.1963, 0.5967, 0.8054, 0.9267, 0.2930, \"3fba47f2\"),\n",
    "    (\"abc785646aff61557c7ed4c8850ea1117c65e8ea\", \"abc78564\", datetime(2024,  4,  5), 0.1878, 0.5878, 0.7231, 0.8906, 0.2978, \"abc78564\"),\n",
    "]\n",
    "\n",
    "df = pd.DataFrame(data=data, columns=columns)\n",
    "data_source = ColumnDataSource(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "  <div id=\"c5f00d44-6823-4878-a9b4-0b348e9bde1f\" data-root-id=\"p1005\" style=\"display: contents;\"></div>\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/javascript": "(function(root) {\n  function embed_document(root) {\n  const docs_json = {\"67a0ecb7-543b-49ba-8f05-80e943eae498\":{\"version\":\"3.6.3\",\"title\":\"Bokeh Application\",\"roots\":[{\"type\":\"object\",\"name\":\"Figure\",\"id\":\"p1005\",\"attributes\":{\"height\":450,\"x_range\":{\"type\":\"object\",\"name\":\"DataRange1d\",\"id\":\"p1006\"},\"y_range\":{\"type\":\"object\",\"name\":\"DataRange1d\",\"id\":\"p1007\"},\"x_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1015\"},\"y_scale\":{\"type\":\"object\",\"name\":\"LinearScale\",\"id\":\"p1016\"},\"title\":{\"type\":\"object\",\"name\":\"Title\",\"id\":\"p1008\",\"attributes\":{\"text\":\"5x5 Wind Farm Timing Test\"}},\"renderers\":[{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1059\",\"attributes\":{\"data_source\":{\"type\":\"object\",\"name\":\"ColumnDataSource\",\"id\":\"p1001\",\"attributes\":{\"selected\":{\"type\":\"object\",\"name\":\"Selection\",\"id\":\"p1002\",\"attributes\":{\"indices\":[],\"line_indices\":[]}},\"selection_policy\":{\"type\":\"object\",\"name\":\"UnionRenderers\",\"id\":\"p1003\"},\"data\":{\"type\":\"map\",\"entries\":[[\"index\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAEAAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABkAAAAaAAAAGwAAABwAAAAdAAAAHgAAAB8AAAAgAAAAIQAAACIAAAAjAAAAJAAAACUAAAAmAAAAJwAAACgAAAApAAAAKgAAACsAAAAsAAAALQAAAC4AAAAvAAAAMAAAADEAAAAyAAAAMwAAADQAAAA1AAAANgAAADcAAAA4AAAAOQAAADoAAAA7AAAAPAAAAD0AAAA+AAAAPwAAAEAAAABBAAAAQgAAAEMAAABEAAAARQAAAEYAAABHAAAASAAAAEkAAABKAAAASwAAAEwAAABNAAAATgAAAE8AAABQAAAAUQAAAFIAAABTAAAAVAAAAFUAAABWAAAAVwAAAFgAAABZAAAAWgAAAFsAAABcAAAAXQAAAF4AAABfAAAA\"},\"shape\":[96],\"dtype\":\"int32\",\"order\":\"little\"}],[\"commit_hash\",{\"type\":\"ndarray\",\"array\":[\"df25a9cfacd3d652361d2bd37f568af00acb2631\",\"b797390a43298a815f3ff57955cfdc71ecf3e866\",\"01a02d5f91b2f4a863eebe88a618974b0749d1c4\",\"dd847210082035d43b0273ae63a76a53cb8d2e12\",\"33779269e98cc882a5f066c462d8ec1eadf37a1a\",\"12890e029a7155b074b9b325d320d1798338e287\",\"66dafc08bd620d96deda7d526b0e4bfc3b086650\",\"a325819b3b03b84bd76ad455e3f9b4600744ba14\",\"8a2c1a610295c007f0222ce737723c341189811d\",\"c6bc79b0cfbc8ce5d6da0d33b68028157d2e93c0\",\"03e1f461c152e4f221fe92c834f2787680cf5772\",\"9e96d6c412b64fe76a57e7de8af3b00c21d18348\",\"2a98428f9c6fb9bb4302ae09809441bf3e7162b0\",\"9b4e85cf1b41ba7001aaba1a830b93e176f3dd43\",\"d18f4d263ecabf502242592f9d60815a07c7b89c\",\"a23241bb9e45078e36a4662d48c9d3fe0c3316e4\",\"c2006b0011a5df036c306c15e75763ec492dafda\",\"0c2adf3e702b6427da946a6ba9dbedbea22738be\",\"39c466000b1874e06a6f58da9c30bb877fc8d4d2\",\"8436fd78b002e5792f5d0dd1409332d171036d49\",\"07a45b66c5facfea06c40bd82e34040c97560640\",\"1d84538c334a502c6ad7df48b8cc2309d6a6436d\",\"4d528a3d6456621a382d409b5145a877b5414b88\",\"8c637b36b66069b216cb94ae87d4c0a91e9b211e\",\"4d23fa6dd78d0497deb4fd62783f0b3ee4204579\",\"015f6874c320efee2c0d1ae76eea4a5b043d69d6\",\"26f06d449da208ce64724b1463b07ad20746cbdc\",\"6b9d6bb8bec6e3ea548f5858e2a8ea5986264fc8\",\"b796bd0fd92ba6b91d590f6cb60bb7ab3bca9932\",\"780aef7c7b4b9cafea3e323d536a34a4af5818b4\",\"9f93ad9bf85e4a0e6baf5b62ea4b3ef143729861\",\"16628a0ba45a675df762245694e0a7666a3478f8\",\"01684c8559604344bd09791268131819a09770a8\",\"e9231fb893c765b723fa4c1e087a58761b6aa471\",\"219889e243ffc69c71b6f7747f5af751d5694de1\",\"6124d2a82a7a823722210bc2e8516d355ba19eb3\",\"f6e4287f712cc866893e71b1ea7a7546e4567bf9\",\"f2797fef396f2f19b02abb1f9555b678dac614f1\",\"b4e538f530048fec58eaca5170be82c67dbdcceb\",\"68820b715ed6b2c981aa11d29c0102e879280d79\",\"03deffeda91fa8d8ab188d57b9fa302a7be008e0\",\"0d2bfecc271d561f67050659684b4797af8ee740\",\"1d03a465593f56c99a64a576d185d4ed17b659f2\",\"78a953b7ef9a36b62e5b446c80ed68abfddbfb74\",\"6c4f70ffbf3d4d2922d41d0032ae1b93d8a23c99\",\"ab03282623d0262b20b8c132efcdcace2dace766\",\"d2f7a45af27a6b40027d6f6a0f4f0be0c6dee5d9\",\"98b23f3d517481b127f190f5f8b7ebfae7f8b6b2\",\"452425de723cc1640d999022389672caf9bffbd0\",\"85dadb1a566c9fa8dc84cb9837b98bd5d23b8d58\",\"432ee7f96c1f6cccd05a0034c86c720cdb63a3e6\",\"ebd70ecaef14c0e239337eb6e36506303378a31a\",\"77fa7155d55bdf3fd43e29f58fe57feffcb107cf\",\"d5d4b1346bd6acba9ba41b4bf546640de162a9d6\",\"d5d4b1346bd6acba9ba41b4bf546640de162a9d6\",\"7c879f1ce18b52d9b0a8eecf877d03e66afc975b\",\"2aa9f2a55686f2ee5dc407e8e0223eb25176d906\",\"5e5bb7f4e653621e7a81ff4bcaa27dbc1f759de7\",\"d91953a499dfb88b457a1e7a07903debbda4058b\",\"76742879c81c9baced49b9fc60abbf1d2eba65ff\",\"9c73a41eaca95bb718ac79980a1799dfa1c48cf3\",\"67104dd714de939be136646af68edd9643ddfcd3\",\"e6906feebdee6bdd2103f0bd390679e6a1b0052d\",\"8908ab47eaa8a3d7e7c9126484b524f751e41f55\",\"063d8b58464f95520c9887ac4f575e6c1f6880d8\",\"59e53a66aef134a3c9e912f9468ca667b599d4e5\",\"cd14608474be8561c188d2aa7a772b8ac753fb70\",\"db958c4b779ffc825689e052958020864cbcde63\",\"8ece0f5f7d3bfd66f4f83198debf5627344af534\",\"77ea50d9bd5d01f7110dbebf1ba689a25eee9d96\",\"05b900c228d427bfa8e531527b546cdeb822cfc9\",\"2dccbbd0ca67a274a2aeb9996f262014b3137fc0\",\"e9c90aa521917e587dd9497d529822f359eec3e2\",\"6c3ddb48b59d286899a8efd5989d741f86c4ade3\",\"31fe1b69ff863f0a610aec5b22424382ec3cc933\",\"a4768d08e172e009efb7ccafb8dc37a90753df7f\",\"1a2e86847d7942d9ecac20d91d2f4cd73685b230\",\"bc4fd2812636baba036d6f5648c6e77bcfb263e4\",\"34a7e0cd84226520f5a39cf3345699f012aad505\",\"e1dd6b73ae1d9552e0fe9679c0d35199c113d647\",\"599f2266ad55f73f4afaf80d4d1e32523a256d3b\",\"52b8a5f595f565b149a227b26bea7786d742f15c\",\"6f2256dab34c9d9548bd6d4d81594605d75434bd\",\"b6de318f12c93872daec8762edecb66d311504b5\",\"94357caf7092f6bfb6d8b51b9daf1ae9b47f26dc\",\"64ae6789f1860734ab4d6d34cd7c4313a85274fc\",\"da61128340ac0e520b4583eb759bf771512332f6\",\"bbcb8c33f4f35036c8156c57cea60fea5c5e17af\",\"ebdf9a146359606dc5e13363beee6dd82ad1c247\",\"b88dc7bb15370da91956ca24db3875245dc073d2\",\"a88a15432ef01f7600e3ccd7b9d2b4ba89a01df0\",\"c7f8f36178f35ccd8e08e0ce10a77fc487f78a14\",\"4b331398bc4a08edcd32539157cff2866f481875\",\"faba9890d5d07d9d8720464547602df1ff73124b\",\"3fba47f290480d1795f2d9f813179bc61844778b\",\"abc785646aff61557c7ed4c8850ea1117c65e8ea\"],\"shape\":[96],\"dtype\":\"object\",\"order\":\"little\"}],[\"commit_hash_8char\",{\"type\":\"ndarray\",\"array\":[\"df25a9cf\",\"b797390a\",\"01a02d5f\",\"dd847210\",\"33779269\",\"12890e02\",\"66dafc08\",\"a325819b\",\"8a2c1a61\",\"c6bc79b0\",\"03e1f461\",\"9e96d6c4\",\"2a98428f\",\"9b4e85cf\",\"d18f4d26\",\"a23241bb\",\"c2006b00\",\"0c2adf3e\",\"39c46600\",\"8436fd78\",\"07a45b66\",\"1d84538c\",\"4d528a3d\",\"8c637b36\",\"4d23fa6d\",\"015f6874\",\"26f06d44\",\"6b9d6bb8\",\"b796bd0f\",\"780aef7c\",\"9f93ad9b\",\"16628a0b\",\"01684c85\",\"e9231fb8\",\"219889e2\",\"6124d2a8\",\"f6e4287f\",\"f2797fef\",\"b4e538f5\",\"68820b71\",\"03deffed\",\"0d2bfecc\",\"1d03a465\",\"78a953b7\",\"6c4f70ff\",\"ab032826\",\"d2f7a45a\",\"98b23f3d\",\"452425de\",\"85dadb1a\",\"432ee7f9\",\"ebd70eca\",\"77fa7155\",\"d5d4b134\",\"d5d4b134\",\"7c879f1c\",\"2aa9f2a5\",\"5e5bb7f4\",\"d91953a4\",\"76742879\",\"9c73a41e\",\"67104dd7\",\"e6906fee\",\"8908ab47\",\"063d8b58\",\"59e53a66\",\"cd146084\",\"db958c4b\",\"8ece0f5f\",\"77ea50d9\",\"05b900c2\",\"2dccbbd0\",\"e9c90aa5\",\"6c3ddb48\",\"31fe1b69\",\"a4768d08\",\"1a2e8684\",\"bc4fd281\",\"34a7e0cd\",\"e1dd6b73\",\"599f2266\",\"52b8a5f5\",\"6f2256da\",\"b6de318f\",\"94357caf\",\"64ae6789\",\"da611283\",\"bbcb8c33\",\"ebdf9a14\",\"b88dc7bb\",\"a88a1543\",\"c7f8f361\",\"4b331398\",\"faba9890\",\"3fba47f2\",\"abc78564\"],\"shape\":[96],\"dtype\":\"object\",\"order\":\"little\"}],[\"date\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AACAyDfgd0IAAEDF0+F3QgAAACsm4ndCAACA9srid0IAAICNFOR3QgAAQPNm5HdCAAAAWbnkd0IAAMC+C+V3QgAAgCRe5XdCAACAJF7ld0IAAIC7p+Z3QgAAQCH65ndCAACA3Krvd0IAAABtLPR3QgAAQJ4j9XdCAAAAvML/d0IAAMBWixh4QgAAQIU5NHhCAAAAWyVJeEIAAAAn5WJ4QgAAACflYnhCAACAt2ZneEIAAEAduWd4QgAAQLQCaXhCAABAtAJpeEIAAMB/p2l4QgAAgHxDa3hCAACAfENreEIAAIB8Q2t4QgAAQOKVa3hCAABA4pVreEIAAEDilWt4QgAAwNvNbnhCAAAADcVveEIAAEA+vHB4QgAAAGnrdHhCAAAAXFt7eEIAAABcW3t4QgAAAFxbe3hCAAAAXFt7eEIAAABcW3t4QgAAAFxbe3hCAAAAXFt7eEIAAMDvQH54QgAAwO9AfnhCAABAu+V+eEIAAEC75X54QgAAQLvlfnhCAABAu+V+eEIAAAAhOH94QgAAQFIvgHhCAABAUi+AeEIAAAC4gYB4QgAAwB3UgHhCAADAtB2CeEIAAMC0HYJ4QgAAwLQdgnhCAADAtB2CeEIAAMAQRId4QgAAwMiQkXhCAAAA+oeSeEIAAAD6h5J4QgAAwF/aknhCAAAAkdGTeEIAAMD2I5R4QgAAwFJKmXhCAAAAG4ubeEIAAADgZ594QgAAAOBnn3hCAABAmxioeEIAAIC/f694QgAAgBumtHhCAAAAfpS2eEIAAAB+lLZ4QgAAAH6UtnhCAADAqMO6eEIAAABxBL14QgAAAHEEvXhCAADAmzPBeEIAAEBn2MF4QgAAAM0qwnhCAADAycbDeEIAAMDJxsN4QgAAwMnGw3hCAACALxnEeEIAAECVa8R4QgAAAJIHxnhCAAAAkgfGeEIAAACSB8Z4QgAAgFAczXhCAAAA1A3YeEIAAMD+PNx4QgAAwB9A5XhCAAAA6IDneEIAAIDhuOp4QgAAgOG46nhC\"},\"shape\":[96],\"dtype\":\"float64\",\"order\":\"little\"}],[\"jensen\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"WKg1zTtO9D/vOEVHcvnlP+SDns2qz80/HVpkO99PzT9xPQrXo3DNP0+vlGWIY80/0ZFc/kP6zT+MSuoENBHOP7AD54wo7c0/3gIJih9jzj/5D+m3rwPPP13cRgN4C9A/gy9MpgpGxT8X2c73U+PFP+2ePCzUmsY/3NeBc0aUxj+TOgFNhA3HPwCRfvs6cMY/ArwFEhQ/xj/y0k1iEFjJP4/k8h/Sb8c/l5APejarxj/+ZffkYaHGP07RkVz+Q8o/eAskKH6MyT9L6gQ0ETbMP52AJsKGp8c/1JrmHafoyD/8GHPXEvLJPwtGJXUCmsg/VFInoImwyT81XrpJDALLP0ymCkYldco/SnuDL0ymyj+3Yn/ZPXnIP7N78rBQa8o/w9MrZRniyD8Ab4EExY/JP3qlLEMc68o/GCZTBaOSyj8gQfFjzF3LP/AWSFD8GMs/ke18PzVeyj8tsp3vp8bLPyJseHqlLMs/jLlrCfmgxz8bDeAtkKDIP6JFtvP91Mg/j8L1KFyPyj9HcvkP6bfHP/fkYaHWNMc/gEi/fR04xz9UdCSX/5DGP4Lix5i7lsg/+zpwzojSxj+I9NvXgXPGP/OOU3Qkl8c/Lv8h/fZ1yD/SAN4CCYrHP6HWNO84Rcc/YOXQItv5xj/Oqs/VVuzHP+/Jw0KtacY/ih9j7lpCxj+qglFJnYDGP+m3rwPnjMg/gnNGlPYGxz+0WfW52orFPynLEMe6uMU/8WPMXUvIxz9rK/aX3ZPHPwYSFD/G3MU/UkmdgCbCxj/D9Shcj8LFP/vL7snDQsU/FK5H4XoUxj/c14FzRpTGP67YX3ZPHsY/KcsQx7q4xT/ByqFFtvPFPw+cM6K0N8g/zTtO0ZFcxj+Cc0aU9gbHP7Kd76fGS8c/RwN4CyQoxj9LWYY41sXFP7AD54wo7cU/Vp+rrdhfxj9z1xLyQc/GPznWxW00gMc/C0YldQKayD+TOgFNhA3HP166SQwCK8c/0gDeAgmKxz/jNhrAWyDJP5kqGJXUCcg/\"},\"shape\":[96],\"dtype\":\"float64\",\"order\":\"little\"}],[\"gauss\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"GJXUCWgi9D+Hp1fKMsTzP8x/SL99HeI/z/dT46Wb4j9OYhBYObTiP+kmMQisHOI/j1N0JJf/4j/129eBc0biPz2bVZ+rreI/u7iNBvAW4j85tMh2vp/iP0cDeAskKOI/W7G/7J484j9/2T15WKjjP90kBoGVQ+M/EHo2qz5X4z+fq63YX3bjP5tVn6ut2OM/2c73U+Ol4z8wKqkT0ETkPwaBlUOLbOM/zqrP1Vbs4z8qOpLLf0jjP13cRgN4C+Q/gQTFjzF34z93LSEf9GzkP3rHKTqSy+M/WvW52or94z9O0ZFc/kPkPxiV1AloIuQ/QfFjzF1L5D/l0CLb+X7kPzAqqRPQROQ/gSbChqdX5D/xY8xdS8jjP0Otad5xiuQ/K/aX3ZOH4z+BJsKGp1fkP7pJDAIrh+Q/2ht8YTJV5D9Ke4MvTKbkPwFNhA1Pr+Q/SL99HThn5D95WKg1zTvkP6qCUUmdgOQ/CD2bVZ+r4z/zH9JvXwfkP4enV8oyxOM/g1FJnYAm5D8LJCh+jLnjP9k9eVioNeM/zF1LyAc94z8bL90kBoHjP9lfdk8eFuQ/HOviNhrA4z8U0ETY8PTiP34dOGdEaeM/MZkqGJXU4z86kst/SL/jP0Ck374OnOM/6gQ0ETY84z8f9GxWfa7iP+XQItv5fuI/3+ALk6mC4T/uWkI+6NniP+CcEaW9weM/jNtoAG+B4j88vVKWIY7hPzarPldbseE/dEaU9gZf4j9a9bnaiv3hP2Kh1jTvOOE/mEwVjErq4j+sHFpkO9/hP/5D+u3rwOE/TKYKRiV14j8H8BZIUPziP1Z9rrZif+E/0NVW7C+74T8wKqkT0ETiP2Dl0CLb+eI/BTQRNjy94j8/xty1hHziPwXFjzF3LeM/PE7RkVz+4T8AAAAAAADiP5Jc/kP67eE/Lv8h/fZ14j9a9bnaiv3hP1uxv+yePOI/9ihcj8L14j97FK5H4XriP89m1edqK+I/8rBQa5p34j8OvjCZKhjjP3PXEvJBz+I/\"},\"shape\":[96],\"dtype\":\"float64\",\"order\":\"little\"}],[\"gch\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"X5hMFYxK+j9IUPwYc9f8P02EDU+vlO8/yjLEsS5u7z9YyjLEsS7wP1jKMsSxLvA/ak3zjlN08D/Mf0i/fR3wP94CCYofY/A/lPYGX5hM7z9/2T15WKjwP2iz6nO1FfA/xY8xdy0h8D9xrIvbaADxP0I+6Nms+vA/seHplbIM8T9JLv8h/fbwP55eKcsQx/A/63O1FfvL8D+mCkYldQLxP+XyH9JvX/A/6Gor9pfd8D+gibDh6ZXwPz81XrpJDPE/WDm0yHa+8D+IY13cRgPxPw4tsp3vp/A/q8/VVuwv8T9CPujZrPrwPyfChqdXyvA/0ZFc/kP68D/XNO84RUfxPyV1ApoIG/E/fGEyVTAq8T97gy9MpgrxP/rt68A5I/E/I9v5fmq88D8ofoy5awnxP9lfdk8eFvE/AAAAAAAA8T/nHafoSC7xP5HtfD81XvE/1lbsL7sn8T8yVTAqqRPxP9JvXwfOGfE/K4cW2c738D/Xo3A9CtfwP2b35GGh1vA/t9EA3gIJ8T/AWyBB8WPwP+XQItv5fvA/hslUwaik8D/kg57Nqs/wP36MuWsJ+fA/UkmdgCbC8D9tVn2utmLwP9nO91PjpfA/rkfhehSu8D8T8kHPZtXwP/s6cM6I0vA/8KfGSzeJ8D+0WfW52orpP6AaL90kBuk/ldQJaCJs5j8KaCJseHrnP5SHhVrTvPA/Dk+vlGWI6T/LEMe6uI3mP6qCUUmdgOY/wTkjSnuD6T+Cc0aU9gbnP2HD0ytlGeY//kP67evA5z90RpT2Bl/mP9Ei2/l+aug/O99PjZdu6D8bL90kBoHpPwrXo3A9Cuc/foy5awn55j+WIY51cRvpP/fkYaHWNOk/hxbZzvdT5z8ydy0hH/ToP/5D+u3rwOk/irDh6ZWy5j80orQ3+MLmP2WqYFRSJ+Y/X5hMFYxK5j/J5T+k377mP5M6AU2EDec/wOyePCzU6D8SFD/G3LXmPyo6kst/SOc/Tx4Wak3z5j9LWYY41sXpP2uad5yiI+c/\"},\"shape\":[96],\"dtype\":\"float64\",\"order\":\"little\"}],[\"cc\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8LRiV1AprzPz9XW7G/7PI/seHplbIM8z/x9EpZhjjzPxB6Nqs+V/M/ylTBqKRO8z89CtejcD3zP2uad5yiI/M/XwfOGVHa8j8tQxzr4jbzPzojSnuDL/M/odY07zhF8z+n6Egu/yHzP7N78rBQa/M/dCSX/5B+8z9F2PD0SlnzP8NkqmBUUvM/mpmZmZmZ8z/7y+7Jw0LzP2ZmZmZmZvM/QfFjzF1L8z/NO07RkVzzP6MBvAUSFPM/0gDeAgmK8z/GbTSAt0DzP50Rpb3BF/M/ayv2l92T8z+6awn5oGfzP7hAguLHmPM/JlMFo5I68z+P5PIf0m/zP0Otad5xivM/KxiV1Alo8z9tVn2utmLzPwN4CyQofvM/ApoIG55e8z9GJXUCmgjzPxueXinLEPM/taZ5xyk68z+MSuoENBHzP5wzorQ3+PI/UrgehetR8z8hH/RsVn3zPyBB8WPMXfM/p+hILv8h8z8wTKYKRiXzP+cdp+hILvM/WRe30QDe8j9uowG8BRLzP76fGi/dJPM/rIvbaABv8z/aG3xhMlXuPwK8BRIUP+4/Di2yne+n7D8PnDOitDfsP03zjlN0JPM/2PD0SlmG7j/PZtXnaivsP4/C9Shcj+w/guLHmLuW7j/zH9JvXwfsP2fV52or9us/rBxaZDvf6z95WKg1zTvsP8bctYR80O0/ArwFEhQ/7D+rPldbsb/sP1YOLbKd7+s/BaOSOgFN7D/Kw0Ktad7tPzMzMzMzM+0/Gw3gLZCg7D9MpgpGJXXuP+F6FK5H4e4/dEaU9gZf7D9dbcX+snvsP6rx0k1iEOw/Io51cRsN7D9qvHSTGATsP4j029eBc+w/2PD0SlmG7D9qvHSTGATsP5MYBFYOLew/1sVtNIC37D+dgCbChqftP8cpOpLLf+w/\"},\"shape\":[96],\"dtype\":\"float64\",\"order\":\"little\"}],[\"emgauss\",{\"type\":\"ndarray\",\"array\":{\"type\":\"bytes\",\"data\":\"AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh//yH99nXg1D+FfNCzWfXVP0+vlGWIY9U/w9MrZRni1D/G3LWEfNDTP8PTK2UZ4tQ/sAPnjCjt1T9d/kP67evUPz7o2az6XNU/B84ZUdob1D92cRsN4C3UP26jAbwFEtQ/ZohjXdxG0z+4QILix5jTP28Sg8DKodU/Ns07TtGR1D+28/3UeOnSP8sQx7q4jdI/ldQJaCJs1D8E54wo7Q3SP7FQa5p3nNI/X5hMFYxK0j+Zu5aQD3rSP3Gsi9toANM/iUFg5dAi0z++wRcmUwXTP9UJaCJseNI/yeU/pN++0j9Wn6ut2F/SPwU0ETY8vdI/i2zn+6nx0j92Tx4Wak3TP+m3rwPnjNQ/9GxWfa620j9DrWnecYrSP8RCrWnecdI/kxgEVg4t0j+6SQwCK4fSPz9XW7G/7NI/63O1FfvL0j/tnjws1JrSPwMJih9j7tI/owG8BRIU0z+Nl24Sg8DSP1fsL7snD9M/\"},\"shape\":[96],\"dtype\":\"float64\",\"order\":\"little\"}],[\"tooltip_label\",{\"type\":\"ndarray\",\"array\":[\"df25a9cf\",\"b797390a\",\"01a02d5f\",\"dd847210\",\"33779269\",\"12890e02\",\"66dafc08\",\"a325819b\",\"8a2c1a61\",\"c6bc79b0\",\"PR #56\",\"v3.0rc1\",\"PR #317\",\"v3.0\",\"v3.0.1\",\"v3.1\",\"v3.1.1\",\"v3.2\",\"v3.2.1\",\"v3.2.2\",\"07a45b66\",\"1d84538c\",\"4d528a3d\",\"8c637b36\",\"4d23fa6d\",\"015f6874\",\"26f06d44\",\"6b9d6bb8\",\"b796bd0f\",\"780aef7c\",\"9f93ad9b\",\"v3.3\",\"01684c85\",\"e9231fb8\",\"219889e2\",\"6124d2a8\",\"f6e4287f\",\"f2797fef\",\"b4e538f5\",\"68820b71\",\"03deffed\",\"0d2bfecc\",\"1d03a465\",\"78a953b7\",\"6c4f70ff\",\"ab032826\",\"d2f7a45a\",\"98b23f3d\",\"452425de\",\"85dadb1a\",\"432ee7f9\",\"ebd70eca\",\"77fa7155\",\"d5d4b134\",\"d5d4b134\",\"7c879f1c\",\"2aa9f2a5\",\"v3.4\",\"d91953a4\",\"76742879\",\"9c73a41e\",\"67104dd7\",\"e6906fee\",\"8908ab47\",\"063d8b58\",\"59e53a66\",\"cd146084\",\"db958c4b\",\"8ece0f5f\",\"77ea50d9\",\"05b900c2\",\"2dccbbd0\",\"e9c90aa5\",\"6c3ddb48\",\"v3.5\",\"a4768d08\",\"1a2e8684\",\"bc4fd281\",\"34a7e0cd\",\"e1dd6b73\",\"599f2266\",\"52b8a5f5\",\"6f2256da\",\"b6de318f\",\"94357caf\",\"64ae6789\",\"da611283\",\"bbcb8c33\",\"ebdf9a14\",\"b88dc7bb\",\"a88a1543\",\"c7f8f361\",\"4b331398\",\"faba9890\",\"3fba47f2\",\"abc78564\"],\"shape\":[96],\"dtype\":\"object\",\"order\":\"little\"}]]}}},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1060\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1061\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1056\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"jensen\"},\"line_color\":\"blue\"}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1057\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"jensen\"},\"line_color\":\"blue\",\"line_alpha\":0.1}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1058\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"jensen\"},\"line_color\":\"blue\",\"line_alpha\":0.2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1070\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1071\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1072\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1067\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"jensen\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"blue\"},\"fill_color\":{\"type\":\"value\",\"value\":\"blue\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1068\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"jensen\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"blue\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.1},\"fill_color\":{\"type\":\"value\",\"value\":\"blue\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.1},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1069\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"jensen\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"blue\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.2},\"fill_color\":{\"type\":\"value\",\"value\":\"blue\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.2},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.2}}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1079\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1080\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1081\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1076\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gauss\"},\"line_color\":\"green\"}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1077\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gauss\"},\"line_color\":\"green\",\"line_alpha\":0.1}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1078\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gauss\"},\"line_color\":\"green\",\"line_alpha\":0.2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1089\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1090\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1091\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1086\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gauss\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"green\"},\"fill_color\":{\"type\":\"value\",\"value\":\"green\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1087\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gauss\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"green\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.1},\"fill_color\":{\"type\":\"value\",\"value\":\"green\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.1},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1088\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gauss\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"green\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.2},\"fill_color\":{\"type\":\"value\",\"value\":\"green\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.2},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.2}}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1098\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1099\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1100\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1095\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gch\"},\"line_color\":\"red\"}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1096\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gch\"},\"line_color\":\"red\",\"line_alpha\":0.1}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1097\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gch\"},\"line_color\":\"red\",\"line_alpha\":0.2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1108\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1109\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1110\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1105\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gch\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"red\"},\"fill_color\":{\"type\":\"value\",\"value\":\"red\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1106\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gch\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"red\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.1},\"fill_color\":{\"type\":\"value\",\"value\":\"red\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.1},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1107\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"gch\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"red\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.2},\"fill_color\":{\"type\":\"value\",\"value\":\"red\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.2},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.2}}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1117\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1118\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1119\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1114\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"cc\"},\"line_color\":\"cyan\"}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1115\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"cc\"},\"line_color\":\"cyan\",\"line_alpha\":0.1}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1116\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"cc\"},\"line_color\":\"cyan\",\"line_alpha\":0.2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1127\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1128\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1129\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1124\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"cc\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"cyan\"},\"fill_color\":{\"type\":\"value\",\"value\":\"cyan\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1125\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"cc\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"cyan\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.1},\"fill_color\":{\"type\":\"value\",\"value\":\"cyan\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.1},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1126\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"cc\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"cyan\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.2},\"fill_color\":{\"type\":\"value\",\"value\":\"cyan\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.2},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.2}}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1136\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1137\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1138\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1133\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"emgauss\"},\"line_color\":\"magenta\"}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1134\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"emgauss\"},\"line_color\":\"magenta\",\"line_alpha\":0.1}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Line\",\"id\":\"p1135\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"emgauss\"},\"line_color\":\"magenta\",\"line_alpha\":0.2}}}},{\"type\":\"object\",\"name\":\"GlyphRenderer\",\"id\":\"p1145\",\"attributes\":{\"data_source\":{\"id\":\"p1001\"},\"view\":{\"type\":\"object\",\"name\":\"CDSView\",\"id\":\"p1146\",\"attributes\":{\"filter\":{\"type\":\"object\",\"name\":\"AllIndices\",\"id\":\"p1147\"}}},\"glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1142\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"emgauss\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"magenta\"},\"fill_color\":{\"type\":\"value\",\"value\":\"magenta\"}}},\"nonselection_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1143\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"emgauss\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"magenta\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.1},\"fill_color\":{\"type\":\"value\",\"value\":\"magenta\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.1},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.1}}},\"muted_glyph\":{\"type\":\"object\",\"name\":\"Scatter\",\"id\":\"p1144\",\"attributes\":{\"x\":{\"type\":\"field\",\"field\":\"date\"},\"y\":{\"type\":\"field\",\"field\":\"emgauss\"},\"size\":{\"type\":\"value\",\"value\":6},\"line_color\":{\"type\":\"value\",\"value\":\"magenta\"},\"line_alpha\":{\"type\":\"value\",\"value\":0.2},\"fill_color\":{\"type\":\"value\",\"value\":\"magenta\"},\"fill_alpha\":{\"type\":\"value\",\"value\":0.2},\"hatch_alpha\":{\"type\":\"value\",\"value\":0.2}}}}}],\"toolbar\":{\"type\":\"object\",\"name\":\"Toolbar\",\"id\":\"p1014\",\"attributes\":{\"tools\":[{\"type\":\"object\",\"name\":\"PanTool\",\"id\":\"p1039\"},{\"type\":\"object\",\"name\":\"WheelZoomTool\",\"id\":\"p1040\",\"attributes\":{\"renderers\":\"auto\"}},{\"type\":\"object\",\"name\":\"BoxZoomTool\",\"id\":\"p1041\",\"attributes\":{\"overlay\":{\"type\":\"object\",\"name\":\"BoxAnnotation\",\"id\":\"p1042\",\"attributes\":{\"syncable\":false,\"line_color\":\"black\",\"line_alpha\":1.0,\"line_width\":2,\"line_dash\":[4,4],\"fill_color\":\"lightgrey\",\"fill_alpha\":0.5,\"level\":\"overlay\",\"visible\":false,\"left\":{\"type\":\"number\",\"value\":\"nan\"},\"right\":{\"type\":\"number\",\"value\":\"nan\"},\"top\":{\"type\":\"number\",\"value\":\"nan\"},\"bottom\":{\"type\":\"number\",\"value\":\"nan\"},\"left_units\":\"canvas\",\"right_units\":\"canvas\",\"top_units\":\"canvas\",\"bottom_units\":\"canvas\",\"handles\":{\"type\":\"object\",\"name\":\"BoxInteractionHandles\",\"id\":\"p1048\",\"attributes\":{\"all\":{\"type\":\"object\",\"name\":\"AreaVisuals\",\"id\":\"p1047\",\"attributes\":{\"fill_color\":\"white\",\"hover_fill_color\":\"lightgray\"}}}}}}}},{\"type\":\"object\",\"name\":\"SaveTool\",\"id\":\"p1049\"},{\"type\":\"object\",\"name\":\"ResetTool\",\"id\":\"p1050\"},{\"type\":\"object\",\"name\":\"HelpTool\",\"id\":\"p1051\"},{\"type\":\"object\",\"name\":\"HoverTool\",\"id\":\"p1052\",\"attributes\":{\"renderers\":\"auto\",\"tooltips\":[[\"git ref\",\"@tooltip_label\"]]}}]}},\"left\":[{\"type\":\"object\",\"name\":\"LinearAxis\",\"id\":\"p1034\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"BasicTicker\",\"id\":\"p1035\",\"attributes\":{\"mantissas\":[1,2,5]}},\"formatter\":{\"type\":\"object\",\"name\":\"BasicTickFormatter\",\"id\":\"p1036\"},\"axis_label\":\"Time to solution (s)\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1037\"}}}],\"below\":[{\"type\":\"object\",\"name\":\"DatetimeAxis\",\"id\":\"p1017\",\"attributes\":{\"ticker\":{\"type\":\"object\",\"name\":\"DatetimeTicker\",\"id\":\"p1018\",\"attributes\":{\"num_minor_ticks\":5,\"tickers\":[{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1019\",\"attributes\":{\"num_minor_ticks\":0,\"mantissas\":[1,2,5],\"max_interval\":500.0}},{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1020\",\"attributes\":{\"num_minor_ticks\":0,\"base\":60,\"mantissas\":[1,2,5,10,15,20,30],\"min_interval\":1000.0,\"max_interval\":1800000.0}},{\"type\":\"object\",\"name\":\"AdaptiveTicker\",\"id\":\"p1021\",\"attributes\":{\"num_minor_ticks\":0,\"base\":24,\"mantissas\":[1,2,4,6,8,12],\"min_interval\":3600000.0,\"max_interval\":43200000.0}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1022\",\"attributes\":{\"days\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1023\",\"attributes\":{\"days\":[1,4,7,10,13,16,19,22,25,28]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1024\",\"attributes\":{\"days\":[1,8,15,22]}},{\"type\":\"object\",\"name\":\"DaysTicker\",\"id\":\"p1025\",\"attributes\":{\"days\":[1,15]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1026\",\"attributes\":{\"months\":[0,1,2,3,4,5,6,7,8,9,10,11]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1027\",\"attributes\":{\"months\":[0,2,4,6,8,10]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1028\",\"attributes\":{\"months\":[0,4,8]}},{\"type\":\"object\",\"name\":\"MonthsTicker\",\"id\":\"p1029\",\"attributes\":{\"months\":[0,6]}},{\"type\":\"object\",\"name\":\"YearsTicker\",\"id\":\"p1030\"}]}},\"formatter\":{\"type\":\"object\",\"name\":\"DatetimeTickFormatter\",\"id\":\"p1031\"},\"axis_label\":\"Commit date\",\"major_label_policy\":{\"type\":\"object\",\"name\":\"AllLabels\",\"id\":\"p1032\"}}}],\"center\":[{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1033\",\"attributes\":{\"axis\":{\"id\":\"p1017\"}}},{\"type\":\"object\",\"name\":\"Grid\",\"id\":\"p1038\",\"attributes\":{\"dimension\":1,\"axis\":{\"id\":\"p1034\"}}},{\"type\":\"object\",\"name\":\"Legend\",\"id\":\"p1062\",\"attributes\":{\"location\":\"bottom_left\",\"border_line_color\":\"black\",\"click_policy\":\"mute\",\"items\":[{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1063\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"jensen\"},\"renderers\":[{\"id\":\"p1059\"},{\"id\":\"p1070\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1082\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"gauss\"},\"renderers\":[{\"id\":\"p1079\"},{\"id\":\"p1089\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1101\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"gch\"},\"renderers\":[{\"id\":\"p1098\"},{\"id\":\"p1108\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1120\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"cc\"},\"renderers\":[{\"id\":\"p1117\"},{\"id\":\"p1127\"},{\"id\":\"p1136\"}]}},{\"type\":\"object\",\"name\":\"LegendItem\",\"id\":\"p1148\",\"attributes\":{\"label\":{\"type\":\"value\",\"value\":\"empirical gauss\"},\"renderers\":[{\"id\":\"p1145\"}]}}]}}]}}]}};\n  const render_items = [{\"docid\":\"67a0ecb7-543b-49ba-8f05-80e943eae498\",\"roots\":{\"p1005\":\"c5f00d44-6823-4878-a9b4-0b348e9bde1f\"},\"root_ids\":[\"p1005\"]}];\n  void root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n  }\n  if (root.Bokeh !== undefined) {\n    embed_document(root);\n  } else {\n    let attempts = 0;\n    const timer = setInterval(function(root) {\n      if (root.Bokeh !== undefined) {\n        clearInterval(timer);\n        embed_document(root);\n      } else {\n        attempts++;\n        if (attempts > 100) {\n          clearInterval(timer);\n          console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\");\n        }\n      }\n    }, 10, root)\n  }\n})(window);",
      "application/vnd.bokehjs_exec.v0+json": ""
     },
     "metadata": {
      "application/vnd.bokehjs_exec.v0+json": {
       "id": "p1005"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "## Run-time performance\n",
    "\n",
    "hover_tool = HoverTool(\n",
    "    tooltips=[\n",
    "        # (\"index\", \"$index\"),\n",
    "        (\"git ref\", \"@tooltip_label\"),\n",
    "        # (\"date\", \"@date\"),\n",
    "    ],\n",
    "    # formatters={\n",
    "    #     '@date': 'datetime',\n",
    "    # },\n",
    ")\n",
    "p = figure(\n",
    "    title=\"5x5 Wind Farm Timing Test\",\n",
    "    x_axis_type=\"datetime\",\n",
    "    tooltips=hover_tool.tooltips,\n",
    "    width=600,\n",
    "    height=450\n",
    ")\n",
    "\n",
    "p.line(\"date\", \"jensen\", source=data_source, color=COLORS[0], legend_label=\"jensen\")\n",
    "p.scatter(\"date\", \"jensen\", source=data_source, line_color=COLORS[0], fill_color=COLORS[0], size=6, legend_label=\"jensen\")\n",
    "p.line(\"date\", \"gauss\", source=data_source, color=COLORS[1], legend_label=\"gauss\")\n",
    "p.scatter(\"date\", \"gauss\", source=data_source, line_color=COLORS[1], fill_color=COLORS[1], size=6, legend_label=\"gauss\")\n",
    "p.line(\"date\", \"gch\", source=data_source, color=COLORS[2], legend_label=\"gch\")\n",
    "p.scatter(\"date\", \"gch\", source=data_source, line_color=COLORS[2], fill_color=COLORS[2], size=6, legend_label=\"gch\")\n",
    "p.line(\"date\", \"cc\", source=data_source, color=COLORS[3], legend_label=\"cc\")\n",
    "p.scatter(\"date\", \"cc\", source=data_source, line_color=COLORS[3], fill_color=COLORS[3], size=6, legend_label=\"cc\")\n",
    "p.line(\"date\", \"emgauss\", source=data_source, color=COLORS[4], legend_label=\"cc\")\n",
    "p.scatter(\"date\", \"emgauss\", source=data_source, line_color=COLORS[4], fill_color=COLORS[4], size=6, legend_label=\"empirical gauss\")\n",
    "\n",
    "p.xaxis.axis_label = \"Commit date\"\n",
    "p.yaxis.axis_label = \"Time to solution (s)\"\n",
    "\n",
    "p.legend.location = \"bottom_left\"\n",
    "p.legend.click_policy=\"mute\"\n",
    "p.legend.border_line_width = 1\n",
    "p.legend.border_line_color = \"black\"\n",
    "p.legend.border_line_alpha = 0.5\n",
    "\n",
    "show(p)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "floris",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.2"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}


================================================
FILE: docs/dev_guide.md
================================================
# Developer's Guide

FLORIS is maintained by NLR.
We are excited about community contribution, and this page outlines
processes and procedures to follow when contributing to the
source code. For technical questions regarding FLORIS usage, please
post your questions to [GitHub Discussions](https://github.com/NatLabRockies/floris/discussions).

## Getting Started

There are a few steps that nearly all contributors will need to go through to get started with
making contributions to FLORIS. Each of these steps will be addressed in a later section of the
developer's guide, so please read on to learn more about each of these steps.

1. Create a fork of FLORIS on GitHub
2. Clone the repository

    ```bash
    git clone -b develop https://github.com/<your-GitHub-username>/floris.git
    ```

3. Move into the FLORIS source code directory

    ```bash
    cd floris/
    ```

4. Install FLORIS in editable mode with the appropriate developer tools

   - ``".[develop]"`` is for the linting and code checking tools
   - ``".[docs]"`` is for the documentation building tools. Ideally, developers should also be
     contributing to the documentation, and therefore checking that the documentation builds locally.

    ```bash
    pip install -e ".[develop, docs]"
    ```
5. Turn on the linting and code checking tools
   ```bash
   pre-commit install
   ```

## Git and GitHub Workflows

The majority of the collaboration and development for FLORIS takes place in
the [GitHub repository](http://github.com/NatLabRockies/floris). There,
[issues](http://github.com/NatLabRockies/floris/issues) and
[pull requests](http://github.com/NatLabRockies/floris/pulls) are managed,
questions and ideas are [discussed](https://github.com/NatLabRockies/floris/discussions),
and [new versions](http://github.com/NatLabRockies/floris/releases)
are released. It is the best mechanism for engaging with the NLR team
and other developers throughout the FLORIS community.

FLORIS development should follow "Git Flow" when interacting with the GitHub
repository. Git Flow is a git workflow outlining safe methods of pushing and
pulling commits to a shared repository. Maintaining this workflow is critical
to prevent remote changes from blocking your local development. The Git Flow
process is detailed nicely [here](http://nvie.com/posts/a-successful-git-branching-model).

### Syncing a local repository with NREL/FLORIS
The "main" FLORIS repository is continuously updated along with ongoing
research at NLR. From time to time, developers of FLORIS using their own
"local" repositories (versions of the software that exist on a local computer)
may want to sync with NREL/FLORIS. To do this, use the following git commands:

```bash
# Move into the FLORIS source code directory;
# this may be named differently on your computer.
cd floris/

# Find the remote name that corresponds to
# NREL/FLORIS; usually "origin" or "upstream".
git remote -v

# Fetch the changes on all remotes.
git fetch --all

# Decide which branch to sync with
# NREL/FLORIS. Generally, this will be "main".
git checkout main
git pull origin main

# Update any local working branches with the
# latest from NREL/FLORIS.
git checkout feature/working_branch
git merge main
```

Note that the example above is a general case and may need to be modified
to fit a specific use case or purpose. If significant development has
happened locally, then [merge conflicts](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts)
are likely and should be resolved as early as possible.


## Code quality tools

FLORIS is configured to use tools to automatically check and enforce
aspects of code quality. In general, these should be adopted by all
developers and incorporated into the development workflow. Most
tools are configured in [pyproject.toml](https://github.com/NatLabRockies/floris/blob/main/pyproject.toml),
but some may have a dedicated configuration file.

### isort

Import lines can easily get out of hand and cause unnecessary distraction
in source code files. [isort](https://pycqa.github.io/isort/index.html)
is used to automatically manage imports in the source code. It can be run
directly with the following command:

```bash
isort <path to file>
isort dir/*
```

This tool was initially configured in [PR#535](https://github.com/NatLabRockies/floris/pull/535),
and additional information on specific decisions can be found there.

### Ruff

[Ruff](https://github.com/charliermarsh/ruff) is a general linter and limited auto-formatter.
It is configured in `pyproject.toml` through various `[tool.ruff.*]` blocks. It is a command line
tool and integrations into popular IDE's are available. A typical command to run Ruff for all of
FLORIS is the following:

```bash
ruff . --fix
```

This sets the configuration from `pyproject.toml`, applies the selected rules to Python files,
and fixes errors in-place where possible.

Ruff was initially configured in [PR#562](https://github.com/NatLabRockies/floris/pull/562), and discussed
in more detail in [D#561](https://github.com/NatLabRockies/floris/discussions/561). See the Ruff
documentation for a list of [supported rules](https://github.com/charliermarsh/ruff#supported-rules)
and [available options for various rules](https://github.com/charliermarsh/ruff#reference).

### Pre-commit

[Pre-commit](https://pre-commit.com) is a utility to execute a series of git-hooks to catch
and fix formatting errors. It integrates easily with other tools, in our case isort and Ruff.
Pre-commit is tightly integrated into git and is mostly not used directly by users.

Once installed, the precommit hooks must be installed into each development environment with
the following command from the `floris/` directory:

```bash
pre-commit install
```

Then, each commit creation with `git` will run the installed hooks and display where
checks have failed. Pre-commit will typically modify the files directly to fix the issues. However,
each file fixed by Pre-commit must be added to the git-commit again to capture the changes. A
typical workflow is given below.

```bash
git add floris/simulation/turbine.py
git commit -m "Update so and so"
> [WARNING] Unstaged files detected.
> [INFO] Stashing unstaged files to /Users/rafmudaf/.cache/pre-commit/patch1675722485-25489.
> isort....................................................................Failed
> - hook id: isort
> - files were modified by this hook
>
> Fixing /Users/rafmudaf/Development/floris/floris/simulation/turbine.py

# Check that the error is fixed or fixed it manually
git status

# Stage the new changes and commit
git add floris/simulation/turbine.py
git commit -m "Update so and so"
```

## Testing

In order to maintain a level of confidence in the software, FLORIS is expected
to maintain a reasonable level of test coverage. To that end, unit
tests for a the low-level code in the `floris.core` package are included.

The full testing suite can by executed by running the command ``pytest`` from
the highest directory in the repository. A testing-only class is included
to provide consistent and convenient inputs to modules at
`floris/tests/conftest.py`.

Unit tests are integrated into FLORIS with [pytest](https://docs.pytest.org/en/latest/),
and they can be executed with the following command:

```bash
cd floris/
pytest tests/*_unit_test.py
```

Regression tests are also included through [pytest](https://docs.pytest.org/en/latest/).
Functionally, the only difference is that the regression tests take more
time to execute and exercise a large portion of the software. These can be
executed with the following command:

```bash
cd floris/
pytest tests/*_regression_test.py
```

### Continuous Integration

Continuous integration is configured with [GitHub Actions](https://github.com/NatLabRockies/floris/actions)
and executes all of the existing tests for every push-event. The configuration file
is located at `floris/.github/workflows/continuous-integration-workflow.yaml`.

## Documentation

The online documentation is built with Jupyter Book which uses Sphinx
as a framework. It is automatically built and hosted by GitHub, but it
can also be compiled locally. Additional dependencies are required
for the documentation, and they are listed in the `project.optional-dependencies` of `pyproject.toml`.
The commands to build the docs are given below. After successfully
compiling, a file should be located at ``docs/_build/html/index.html``.
This file can be opened in any browser.

```bash
pip install -e ".[docs]"
jupyter-book build docs/

# Lots of output to the terminal here...

open docs/_build/html/index.html
```

## Release guide

Follow the process outlined here to "release" FLORIS.
After completing these steps, a few additional automated processes
are launched to deploy FLORIS to PyPI and conda-forge.
Be sure to complete each step in the sequence as described.

1. Merge the `develop` branch into `main` with a pull request.
    Create a pull request titled `FLORIS vN.M` with version number filled in
    as appropriate.
    The body of the pull request should a brief summary of the changes
    as well as a listing of the major changes and their associated pull requests.
    Since creating the pull request does not mean it is merged, it is
    reasonable to create the pull request, and edit the body of the pull
    request later.
    The pull request template has a checklist at the bottom that should be
    uncommented for this PR.

2. Update the version number and commit to the `develop`` branch
    with a commit message such as "Update version to vN.M".
    The version number must be updated in the following two files:
    - [floris/README.md](https://github.com/NatLabRockies/floris/blob/main/README.md)
    - [pyproject.toml](https://github.com/NatLabRockies/floris/blob/main/pyproject.toml)
    Note that a `.0` version number is left off meaning that valid versions
    are `v3`, `v3.1`, `v3.1.1`, etc.

3. Verify that the documentation is building correctly.
    The docs build for every commit to `develop`, so there should be no
    surprises in this regard prior to a release. However, it's a good
    opportunity to ensure that the documentation is up to date and there
    are no obvious issues.
    Check this by opening the documentation website at https://natlabrockies.github.io/floris
    and scrolling through the pages.
    Also, verify that the automated build process has successfully completed
    for the commits to `develop` in [GitHub Actions](https://github.com/NatLabRockies/floris/actions/workflows/deploy-pages.yaml).

4. The changes since the prior commit can be gotten from GitHub by going through the
    process to create a release, but stopping short of actually publishing it.
    In this form, GitHub provides the option to autogenerate release notes.
    Be sure to choose the correct starting tag, and then hit "Generate release notes".
    Then, copy the generated text into the pull request body, and format it
    as appropriate. A good reference is typically the previous release.

5. Merge the pull request into `main`. Select "Create a merge commit" from the merge
    dropdown, and hit "Merge pull request".

6. Create a [new release](https://github.com/NatLabRockies/floris/releases/new) on GitHub
    with the title "vN.M". Choose to create a new tag on publish with the same
    name. Also, autogenerate the release notes again. If you autogenerated the release
    notes in step 4, make sure to start this step from a new browser window.
    Be sure that the "Set as latest release" radio button is enabled.

7. Double check everything.

8. Hit "Publish release".

9. Go to GitHub Actions and watch the [Upload Python Package](https://github.com/NatLabRockies/floris/actions/workflows/python-publish.yml)
    job complete. Upon success, FLORIS will be uploaded to PyPI for installation with pip.
    If it fails, the latest release will not be distributed.

10. Merge the main branch into develop to align all branches on all remotes.

11. That's it, well done!

## Deploying to pip

Generally, only NLR developers will have appropriate permissions to deploy
FLORIS updates. When the time comes, here is a great reference on doing it
is available [here](https://medium.freecodecamp.org/how-to-publish-a-pyton-package-on-pypi-a89e9522ce24).

## Extending the models

The FLORIS architecture is designed to support adding new wake models relatively easily.
Each of the following components have a general API that support plugging in to the rest of the
FLORIS framework:
- Velocity deficit
- Wake deflection
- Added turbulence due to the turbine wake
- Wake combination
- Solver algorithm
- Grid-points

Initially, it's recommended to copy an existing model as a starting point, and the
[Jensen](https://github.com/NatLabRockies/floris/blob/main/floris/simulation/wake_velocity/jensen.py) and
[Jimenez](https://github.com/NatLabRockies/floris/blob/main/floris/simulation/wake_deflection/jimenez.py)
models are good choices due to their simplicity.
New models must be registered in
[Wake.model_map](https://github.com/NatLabRockies/floris/blob/main/floris/simulation/wake.py#L45)
so that they can be enabled via the input dictionary.

```{mermaid}
classDiagram

    class Floris

    class Farm

    class FlowField {
        u: NDArrayFloat
        v: NDArrayFloat
        w: NDArrayFloat
    }

    class Grid {
        <<interface>>
        x: NDArrayFloat
        y: NDArrayFloat
        z: NDArrayFloat
    }

    class WakeModelManager {
        <<interface>>
        combination_model: BaseModel
        deflection_model: BaseModel
        velocity_model: BaseModel
        turbulence_model: BaseModel
    }

    class Solver {
        <<interface>>
        parameters: dict
    }

    class BaseModel {
        prepare_function() dict
        function() None
    }

    Floris *-- Farm
    Floris *-- FlowField
    Floris *-- Grid
    Floris *-- WakeModelManager
    Floris --> Solver

    Solver --> Farm
    Solver --> FlowField
    Solver --> Grid
    Solver --> WakeModelManager

    WakeModelManager -- BaseModel

    style Grid stroke:#FF496B, stroke-width:2px
    style WakeModelManager stroke:#FF496B, stroke-width:2px
    style Solver stroke:#FF496B, stroke-width:2px
```

All of the models have a `prepare_function` and a `function` method.
The `prepare_function` allows the model classes to extract any information from the `Grid` and
`FlowField` data structures, and this is generally used for sizing the data arrays.
The `prepare_function` should return a dictionary that will ultimately be passed to the
`function`.
The `function` method is where the actual calculation is performed.
The API is dependent on the type of model, but generally it requires some indicationg of
the location of the current turbine in the solve step and some other information about the
atmospheric conditions and operation of the turbine.
Note the `*` in the function signature, which is a Python feature that allows
any number of arguments to be passed to the function after the `*` as keyword arguments.
Typically, these arguments are the ones returned from the `prepare_function`.

```python
def prepare_function(self, grid: Grid, flow_field: FlowField) -> Dict[str, Any]

def function(
    self,
    x_i: np.ndarray,
    y_i: np.ndarray,
    z_i: np.ndarray,
    axial_induction_i: np.ndarray,
    deflection_field_i: np.ndarray,
    yaw_angle_i: np.ndarray,
    turbulence_intensity_i: np.ndarray,
    ct_i: np.ndarray,
    hub_height_i: np.ndarray,
    rotor_diameter_i: np.ndarray,
    *,
    variables_from_prepare_function: dict
) -> None:
```

Some models require a special grid and/or solver, and that mapping happens in
[floris.core.core.Core](https://github.com/NatLabRockies/floris/blob/main/floris/core/core.py).
Generally, a specific kind of solver requires one or a number of specific grid-types.
For example, `full_flow_sequential_solver` requires either `FlowFieldGrid` or
`FlowFieldPlanarGrid`.
So, it is often the case that adding a new solver will require adding a new grid type, as well.


================================================
FILE: docs/empirical_gauss_model.md
================================================

(empirical_gauss_model)=
# Empirical Gaussian model

FLORIS's "empirical" model has the same Gaussian wake shape as other popular
FLORIS models. However, the models that describe the wake width and deflection
have been reorganized to provide simpler tuning and data fitting.

## Wake shape

The velocity deficit at a point $(x, y, z)$ in the wake follows a Gaussian
curve, i.e.,

$$ \frac{u}{U_\infty} = 1 - Ce^{-\frac{(y-\delta_y)^2}{2\sigma_y^2} -\frac{(z-z_h-\delta_z)^2}{2\sigma_z^2}} $$

where the $(x, y, z)$ origin is at the turbine location (at ground level).
The terms $C$, $\sigma_y$, $\sigma_z$, $\delta_y$, and $\delta_z$ all depend
on the downstream location $x$.

$C$ is the scaling factor for the Gaussian curve, defined as

$$C = \frac{1}{8\sigma_{0_D}^2}\left(1 - \sqrt{1 - \frac{\sigma_{y0} \sigma_{z0} C_T}{\sigma_y \sigma_z}}\right)$$

Here, $C_T$ is the turbine thrust coefficient, which includes any reduction
in thrust due to yaw or tilt of the turbine rotor. $\sigma_{y0}$ and
$\sigma_{z0}$ define the wake width at the turbine location $x=0$, which are
based on the user-specified rotor-diameter normalized initial width
$\sigma_{0_D}$. Note that
this contrasts with FLORIS's
other Gaussian models, where $\sigma_{y0}$ and $\sigma_{z0}$ are defined at
the end of the near wake/beginning of the far wake, at some $x_0 > 0$. The
normalization term $8\sigma_{0_D}^2$ provides consistency with actuator
disc theory.

## Wake expansion
The wake lateral and vertical widths, $\sigma_y$ and $\sigma_z$, respectively,
are a function of downstream distance $x$. The expansion of the wake is
described by a user-tunable, piecewise linear function. This is simplest to
express as an integral of a piecewise constant wake expansion rate $k$, i.e.,

$$ \sigma_{y}(x) = \int_{0}^x \sum_{i=0}^n k_i \mathbf{1}_{[b_{i}, b_{i+1})} (x') dx' + \sigma_{y0} $$

Here, $\mathbf{1}_{[a, b)}(x)$ is the indicator function, which takes value
1 when $a \leq x < b$, and 0 otherwise.
The above function ensures that expansion rate $k_i$ applies only between
breakpoints $b_{i-1}$ and $b_i$, allowing $n+1$ varying rates of linear
expansion at different downstream ranges, determined by the $b_i$. Note that
$b_0 = 0$ and $b_{n+1} = \infty$ by design.

A slight modification is made to the above so that the wake width varies
smoothly. As stated above, the wake expansion rate contains jump
discontinuities that create "sharp" changes in the wake width. To avoid this,
the indicator function $\mathbf{1}_{[a, b)}(x)$ is replaced with a pair of
"smoothstep" functions that vary smoothly with width parameter $d$. In the
limit as $d\rightarrow 0$, the approximation becomes exact.

While the form of this wake expansion model seems complex, it is very simple
to tune to fit data: the user provides the $n+1$ expansion rates
$k_i, i=0,\dots,n+1$
(defined as a list in the `wake_expansion_rates` field of the input yaml)
and
the $n$ 'break points' $b_i, i=1,\dots,n$ where those expansion rates should go
into effect (specified in terms of rotor diameters downstream as a list in the
`breakpoints_D` field of the input yaml.

As well as these, the initial width $\sigma_{0_D}$ should be
provided by setting `sigma_0_D` and the
logistic function width $d$ as `smoothing_length_D` (both specified in
terms of rotor diameters).

We expect that the default values for $\sigma_{0_D}$ and $d$ should be
satisfactory for most users. Further, we anticipate that most users will not
need more than $n+1=3$ expansion rates (along with $n=2$ break points) to
describe the wake expansion.

## Wake deflection

The deflection of the wake centerline $\delta_y$ and $\delta_z$ due to
yawing and tilting, respectively, follow a simple model

$$ \delta = k_\text{def} C_T \alpha \operatorname{ln}\left(\frac{x/D - c}{x/D + c} + 2\right)$$

Here, $k_\text{def}$ is a user-tunable deflection gain and $\alpha$ is the
misalignment. When computing the lateral wake deflection $\delta_y$ due to
yaw misalignment, $\alpha$ should be the yaw misalignment _specified in
radians, clockwise positive from the wind direction_. When
computing the vertical wake deflection $\delta_z$ due to rotor tilt,
$\alpha$ should be the tilt angle _specified in radians, clockwise positive
when the rotor is tilted back_.

Finally, $c$ in the above deflection model is a 'deflection rate'. This
specifies how quickly the wake will reach it's maximum deflection
$k_\text{def} C_T \alpha \operatorname{ln}(3)$ for a given
yaw/tilt angle.

User-tunable parameters of the model are as follows:
- A separately tunable deflection gain $k_\text{def}$ for each of
lateral deflections (due to yaw misalignments) and vertical deflections
(due to nonzero tilt), specified using `horizontal_deflection_gain_D` and
`vertical_deflection_gain_D` (specified in terms of rotor diameters)
- The deflection rate $c$, specified using `deflection_rate`.

We anticipate that most users will be able to use the default value for $c$,
and set `vertical_deflection_gain_D` to the same value as
`horizontal_deflection_gain_D` (which can also be achieved by providing
`vertical_deflection_gain_D = -1`).

## Wake-induced mixing

Finally, turbines contribute to mixing in the flow. In other models, this
extra mixing is accounted for by adding to the turbulence intensity value. In
the empirical model, explicit dependencies on turbulence intensity are removed
completely to aid in tuning. Instead, a non-physical "wake-induced mixing
factor" is specified for turbine $j$ as

$$ \text{WIM}_j = \sqrt{\sum_{i \neq j}
\left(\frac{A_{ij} a_i} {\bar{d}_{ij}^2}\right)^2} $$

where $A_{ij}$ is the area of overlap of the wake of turbine $i$
onto turbine $j$; $a_i$ is the axial induction factor of the
turbine $i$;
and $\bar{d}_{ij} = (x_j - x_i)/D_i$ is the downstream distance of turbine $j$ from
the turbine $i$, normalized by turbine $i$'s rotor diameter. Here, $A_{ij} = 1$ if turbine $j$ is fully covered by turbine $i$'s wake; $A_{ij} = 0$ if turbine $j$ is not covered at all by turbine $i$'s wake; and $0 < A_{ij} < 1$ if turbine $j$ is partially covered by turbine $i$'s wake. By convention, $A_{ii} = 0$ and $A_{ij} = 0$ if $x_j \leq x_i$ (turbine $j$ is upstream of turbine $i$).

Wake-induced mixing can affect both the velocity deficit and wake deflection.
To account for wake-induced mixing, the wake width of turbine $j$ is adjusted
to

$$ \sigma_{y}(x) = \int_{0}^x \sum_{i=0}^n k_i \ell_{[b_{i}, b_{i+1})}(x') + w_v \text{WIM}_j   dx' + \sigma_{y0} $$

where $w_v$ is the velocity deficit wake-induced mixing gain, which the
user can vary by setting `wim_gain_velocity` to represent different levels of
mixing caused by the turbines.

The wake deflection model is similarly adjusted to

$$ \delta = \frac{k_\text{def} C_T \alpha}{1 + w_d \text{WIM}_j}\operatorname{ln}\left(\frac{x/D - c}{x/D + c} + 2\right)$$

where $w_d$ is the wake-induced mixing gain for deflection, provided by the
user by setting `wim_gain_deflection`.

```{note}
The documentation previously had an erroneous form for the wake-induced mixing
term,

$$ \text{WIM}_j = \sum_{i \in T^{\text{up}}(j)} \frac{A_{ij} a_i} {(x_j - x_i)/D_i} \:.$$

This has been corrected to the form shown above, which is consistent with the implementation. The implementation has not changed; only the documentation has been corrected.
```

## Yaw added mixing

Yaw misalignment can also add turbulence to the wake. In the empirical Gaussian
model, this effect, referred to as "yaw-added wake recovery" in other models,
is activated by setting
`enable_yaw_added_recovery` to `true`. Yaw-added mixing is represented
by updating the wake-induced mixing term as follows:

$$ \text{WIM}_j = \sqrt{\sum_{i \neq j} \left(\frac{A_{ij} a_i (1 + g_\text{YAM} (1-\cos(\gamma_i)))}{\bar{d}_{ij}^2}\right)^2 + \left(a_j g_\text{YAM} (1-\cos(\gamma_j))\right)^2}$$

Note that the second term means that, unlike when `enable_yaw_added_recovery`
is `false`, a turbine may affect the recovery of its own wake by yawing.

## Mirror wakes

Mirror wakes are also enabled by default in the empirical model to model the
ground effect. Essentially, turbines are placed below the ground so that
the vertical expansion of their (mirror) wakes appears in the above-ground
flow some distance downstream, to model the reflection of the true turbine
wakes as they bounce off of the ground/sea surface.

## Added mixing by active wake control

As the name suggests, active wake control (AWC) aims to enhance mixing to the
wake of the controlled turbine. This effect is activated by setting
`enable_active_wake_mixing` to `true`, and `awc_modes` to `"helix"` (other AWC
strategies are yet to be implemented). The wake can then be controlled by
setting the amplitude of the AWC excitation using `awc_amplitudes` (see the
[AWC operation model](operation_models_user.ipynb#awc-model)).
The effect of AWC is represented by updating the
wake-induced mixing term as follows:

$$ \text{WIM}_j = \sqrt{\sum_{i \neq j} \left(\frac{A_{ij} a_i}{\bar{d}_{ij}^2}\right)^2 + \left(\frac{\beta_{j}^{p_\text{AWC}}}{d_\text{AWC}}\right)^2}$$

where $\beta_{j}$ is the AWC amplitude of turbine $j$, and the exponent $p_\text{AWC}$ and
denominator $d_\text{AWC}$ are tuning parameters that can be set in the `emgauss.yaml` file with
the fields `awc_wake_exp` and `awc_wake_denominator`, respectively.
Note that, in contrast to the yaw added mixing case, a turbine currently affects _only_ its own
wake by applying AWC.


================================================
FILE: docs/floating_wind_turbine.md
================================================

# Floating Wind Turbine Modeling

The FLORIS wind turbine description includes a definition of the performance curves
(`power` and `thrust_coefficient`) as a function of wind speed, and this lookup table is used
directly in the calculation of power production for a steady-state atmospheric condition
(wind speed and wind direction). The power curve definition typically assumes a
fixed-bottom wind turbine with a fixed shaft tilt. However, floating
wind turbines have an additional rotational degrees of freedom in the platform pitch, which
adds a tilt angle to the rotor. As the turbine tilts, its performance is affected
because the turbine is no longer operating on its defined performance curve.

FLORIS allows the user to correct for the tilt angle of the turbine as a function of wind speed.
This is accomplished by including an additional input, `floating_tilt_table`, in the turbine definition that sets the steady tilt angle of the turbine based on wind speed. An interpolation is created and the tilt angle is computed for each turbine based on its rotor effective velocity. Taking into account the turbine rotor's built-in tilt, the absolute tilt is used to compute the power and thrust coefficient. To enable the use of the `floating_tilt_table`, the `correct_cp_ct_for_tilt` input on the turbine definition should be set to `True`.

The tilt angle is then used directly in the selected wake models to compute wake effects of tilted turbines.


================================================
FILE: docs/floris_models.ipynb
================================================
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(floris_models)=\n",
    "\n",
    "# FLORIS Models\n",
    "\n",
    "This notebook provides information on the provided FlorisModels. [Introductory Concepts](intro_concepts) introduced `FlorisModel` as the base class for all models in the FLORIS package. This notebook introduces the `ParFlorisModel`, `UncertainFlorisModel`, and `ApproxFlorisModel` classes, which are subclasses or compositions of `FlorisModel`.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Parallelized FLORIS Model\n",
    "\n",
    "The `ParFlorisModel` class is a subclass of `FlorisModel` that parallelizes the FLORIS calculations. This class is designed to \n",
    "have an interface that is the same as `FlorisModel`, but the calculations are parallelized. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Instantiation\n",
    "\n",
    "The `ParFlorisModel` class can be instantiated in the same way as the `FlorisModel` class, or else it can be instantiated by passing a `FlorisModel` object to the constructor. \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from floris import FlorisModel, ParFlorisModel, TimeSeries\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "fmodel = FlorisModel(\"gch.yaml\")\n",
    "\n",
    "# Instantiation using yaml input file\n",
    "pfmodel = ParFlorisModel(\"gch.yaml\")\n",
    "\n",
    "# Instantiation using fmodel\n",
    "pfmodel = ParFlorisModel(fmodel)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parameters\n",
    "\n",
    "The `ParFlorisModel` class has additional parameters the define the parallelization. These parameters are:\n",
    "\n",
    "**interface**: The parallelization interface to use. Options are `\"multiprocessing\"`,\n",
    "    `\"pathos\"`, and `\"concurrent\"`, with possible future support for `\"mpi4py\"`\n",
    "\n",
    "**max_workers**: The maximum number of workers to use. Defaults to -1, which then\n",
    "    takes the number of CPUs available.\n",
    "\n",
    "**n_wind_condition_splits**: The number of wind conditions to split the simulation over.\n",
    "    Defaults to the same as max_workers.\n",
    "\n",
    "**return_turbine_powers_only**: Whether to return only the turbine powers.\n",
    "\n",
    "**print_timings** (bool): Print the computation time to the console. Defaults to False."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Alternative parameters\n",
    "pfmodel = ParFlorisModel(fmodel, max_workers=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Usage\n",
    "\n",
    "The `ParFlorisModel` class can be used in the same way as the `FlorisModel` class. The only difference is that the calculations are parallelized. \n",
    "\n",
    "```python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set to a two turbine layout\n",
    "layout_x = [0, 500]\n",
    "layout_y = [0, 0]\n",
    "fmodel.set(layout_x=layout_x, layout_y=layout_y)\n",
    "pfmodel.set(layout_x=layout_x, layout_y=layout_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "wind_directions = np.arange(240, 300, 0.5)\n",
    "time_series = TimeSeries(\n",
    "    wind_directions=wind_directions, wind_speeds=8.0, turbulence_intensities=0.06\n",
    ")\n",
    "fmodel.set(wind_data=time_series)\n",
    "pfmodel.set(wind_data=time_series)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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
Download .txt
gitextract_8emkfpo1/

├── .codecov.yml
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   ├── config.yml
│   │   └── feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── check-working-examples.yaml
│       ├── continuous-integration-workflow.yaml
│       ├── deploy-pages.yaml
│       ├── python-publish.yml
│       └── quality-metrics-workflow.yaml
├── .gitignore
├── .pre-commit-config.yaml
├── CONTRIBUTING.md
├── LICENSE.txt
├── README.md
├── benchmarks/
│   └── bench.py
├── docs/
│   ├── .nojekyll
│   ├── _config.yml
│   ├── _toc.yml
│   ├── advanced_concepts.ipynb
│   ├── api_docs.md
│   ├── architecture.md
│   ├── bibliography.md
│   ├── code_quality.ipynb
│   ├── dev_guide.md
│   ├── empirical_gauss_model.md
│   ├── floating_wind_turbine.md
│   ├── floris_models.ipynb
│   ├── heterogeneous_map.ipynb
│   ├── index.md
│   ├── input_reference_main.md
│   ├── input_reference_turbine.md
│   ├── installation.md
│   ├── intro_concepts.ipynb
│   ├── layout_optimization.md
│   ├── multidimensional_wind_turbine.ipynb
│   ├── operation_models_user.ipynb
│   ├── references.bib
│   ├── turbine_library.md
│   ├── turbine_models.ipynb
│   ├── v3_to_v4.md
│   ├── wake_models.ipynb
│   └── wind_data_user.ipynb
├── examples/
│   ├── 001_opening_floris_computing_power.py
│   ├── 002_visualizations.py
│   ├── 003_wind_data_objects.py
│   ├── 004_set.py
│   ├── 005_getting_power.py
│   ├── 006_get_farm_aep.py
│   ├── 007_sweeping_variables.py
│   ├── 008_uncertain_models.py
│   ├── 009_parallel_models.py
│   ├── 010_compare_farm_power_with_neighbor.py
│   ├── _convert_examples_to_notebooks.py
│   ├── examples_control_optimization/
│   │   ├── 001_opt_yaw_single_ws.py
│   │   ├── 002_opt_yaw_single_ws_uncertain.py
│   │   ├── 003_opt_yaw_multiple_ws.py
│   │   ├── 004_optimize_yaw_aep.py
│   │   ├── 005_optimize_yaw_aep_parallel.py
│   │   ├── 006_compare_yaw_optimizers.py
│   │   ├── 007_optimize_yaw_with_neighbor_farms.py
│   │   └── 008_optimize_yaw_with_disabled_turbines.py
│   ├── examples_control_types/
│   │   ├── 001_derating_control.py
│   │   ├── 002_disable_turbines.py
│   │   ├── 003_setting_yaw_and_disabling.py
│   │   ├── 004_helix_active_wake_mixing.py
│   │   └── 005_peak_shaving.py
│   ├── examples_emgauss/
│   │   ├── 001_empirical_gauss_velocity_deficit_parameters.py
│   │   └── 002_empirical_gauss_deflection_parameters.py
│   ├── examples_floating/
│   │   ├── 001_floating_turbine_models.py
│   │   ├── 002_floating_vs_fixedbottom_farm.py
│   │   └── 003_tilt_driven_vertical_wake_deflection.py
│   ├── examples_get_flow/
│   │   ├── 001_extract_wind_speed_at_turbines.py
│   │   ├── 002_extract_wind_speed_at_points.py
│   │   ├── 003_extract_turbulence_intensity_at_points.py
│   │   └── 004_plot_velocity_deficit_profiles.py
│   ├── examples_heterogeneous/
│   │   ├── 001_heterogeneous_inflow_single.py
│   │   ├── 002_heterogeneous_using_wind_data.py
│   │   ├── 003_heterogeneous_speedup_by_wd_and_ws.py
│   │   └── 004_heterogeneous_2d_and_3d.py
│   ├── examples_layout_optimization/
│   │   ├── 001_optimize_layout.py
│   │   ├── 002_optimize_layout_with_heterogeneity.py
│   │   ├── 003_genetic_random_search.py
│   │   ├── 004_generate_gridded_layout.py
│   │   └── 005_layout_optimization_complex_boundary.py
│   ├── examples_load_optimization/
│   │   ├── 001_lti_and_voc.py
│   │   └── 002_row_opt_example.py
│   ├── examples_multidim/
│   │   ├── 001_multi_dimensional_cp_ct.py
│   │   ├── 002_multi_dimensional_cp_ct_2Hs.py
│   │   └── 003_multi_dimensional_cp_ct_TI.py
│   ├── examples_operation_models/
│   │   └── 001_compare_yaw_loss.py
│   ├── examples_turbine/
│   │   ├── 001_reference_turbines.py
│   │   ├── 002_multiple_turbine_types.py
│   │   └── 003_specify_turbine_power_curve.py
│   ├── examples_turbopark/
│   │   ├── 001_compare_turbopark_implementations.py
│   │   └── comparison_data/
│   │       ├── Rowpark_Orsted.csv
│   │       └── WindDirection_Sweep_Orsted.csv
│   ├── examples_uncertain/
│   │   ├── 001_uncertain_model_params.py
│   │   ├── 002_approx_floris_model.py
│   │   └── 003_uncertain_model_with_parallelization.py
│   ├── examples_visualizations/
│   │   ├── 001_layout_visualizations.py
│   │   ├── 002_visualize_y_cut_plane.py
│   │   ├── 003_visualize_cross_plane.py
│   │   ├── 004_visualize_rotor_values.py
│   │   └── 005_visualize_flow_by_sweeping_turbines.py
│   ├── examples_wind_data/
│   │   ├── 001_wind_data_comparisons.py
│   │   ├── 002_generate_ti.py
│   │   └── 003_generate_value.py
│   ├── examples_wind_resource_grid/
│   │   ├── 000_generate_example_wrg.py
│   │   ├── 001_wind_rose_wrg.py
│   │   ├── 002_set_floris_with_wrg.py
│   │   ├── 003_wrg_compar_layout_optimization.py
│   │   └── wrg_example.wrg
│   ├── inputs/
│   │   ├── cc.yaml
│   │   ├── emgauss.yaml
│   │   ├── emgauss_helix.yaml
│   │   ├── gch.yaml
│   │   ├── gch_heterogeneous_inflow.yaml
│   │   ├── gch_multi_dim_cp_ct.yaml
│   │   ├── gch_multi_dim_cp_ct_TI.yaml
│   │   ├── gch_multiple_turbine_types.yaml
│   │   ├── jensen.yaml
│   │   ├── turbine_files/
│   │   │   ├── iea_15MW_multi_dim_TI.csv
│   │   │   └── iea_15MW_multi_dim_TI.yaml
│   │   ├── turbopark.yaml
│   │   ├── turbopark_cubature.yaml
│   │   ├── turboparkgauss.yaml
│   │   ├── turboparkgauss_cubature.yaml
│   │   └── wind_rose.csv
│   └── inputs_floating/
│       ├── emgauss_fixed.yaml
│       ├── emgauss_floating.yaml
│       ├── emgauss_floating_fixedtilt15.yaml
│       ├── emgauss_floating_fixedtilt5.yaml
│       ├── gch_fixed.yaml
│       ├── gch_floating.yaml
│       ├── gch_floating_defined_floating.yaml
│       └── turbine_files/
│           ├── nrel_5MW_fixed.yaml
│           ├── nrel_5MW_floating.yaml
│           ├── nrel_5MW_floating_defined_floating.yaml
│           ├── nrel_5MW_floating_fixedtilt15.yaml
│           └── nrel_5MW_floating_fixedtilt5.yaml
├── floris/
│   ├── __init__.py
│   ├── convert_floris_input_v3_to_v4.py
│   ├── convert_turbine_v3_to_v4.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── core.py
│   │   ├── farm.py
│   │   ├── flow_field.py
│   │   ├── grid.py
│   │   ├── rotor_velocity.py
│   │   ├── solver.py
│   │   ├── turbine/
│   │   │   ├── __init__.py
│   │   │   ├── controller_dependent_operation_model.py
│   │   │   ├── operation_models.py
│   │   │   ├── turbine.py
│   │   │   └── unified_momentum_model.py
│   │   ├── wake.py
│   │   ├── wake_combination/
│   │   │   ├── __init__.py
│   │   │   ├── fls.py
│   │   │   ├── max.py
│   │   │   └── sosfs.py
│   │   ├── wake_deflection/
│   │   │   ├── __init__.py
│   │   │   ├── empirical_gauss.py
│   │   │   ├── gauss.py
│   │   │   ├── jimenez.py
│   │   │   └── none.py
│   │   ├── wake_turbulence/
│   │   │   ├── __init__.py
│   │   │   ├── crespo_hernandez.py
│   │   │   ├── none.py
│   │   │   └── wake_induced_mixing.py
│   │   └── wake_velocity/
│   │       ├── __init__.py
│   │       ├── cumulative_gauss_curl.py
│   │       ├── empirical_gauss.py
│   │       ├── gauss.py
│   │       ├── jensen.py
│   │       ├── none.py
│   │       ├── turbopark.py
│   │       ├── turbopark_lookup_table.mat
│   │       └── turboparkgauss.py
│   ├── cut_plane.py
│   ├── default_inputs.yaml
│   ├── floris_model.py
│   ├── flow_visualization.py
│   ├── heterogeneous_map.py
│   ├── layout_visualization.py
│   ├── logging_manager.py
│   ├── optimization/
│   │   ├── __init__.py
│   │   ├── layout_optimization/
│   │   │   ├── __init__.py
│   │   │   ├── layout_optimization_base.py
│   │   │   ├── layout_optimization_boundary_grid.py
│   │   │   ├── layout_optimization_gridded.py
│   │   │   ├── layout_optimization_pyoptsparse.py
│   │   │   ├── layout_optimization_pyoptsparse_spread.py
│   │   │   ├── layout_optimization_random_search.py
│   │   │   └── layout_optimization_scipy.py
│   │   ├── load_optimization/
│   │   │   ├── __init__.py
│   │   │   └── load_optimization.py
│   │   ├── other/
│   │   │   ├── __init__.py
│   │   │   └── boundary_grid.py
│   │   └── yaw_optimization/
│   │       ├── __init__.py
│   │       ├── yaw_optimization_base.py
│   │       ├── yaw_optimization_tools.py
│   │       ├── yaw_optimizer_geometric.py
│   │       ├── yaw_optimizer_scipy.py
│   │       └── yaw_optimizer_sr.py
│   ├── par_floris_model.py
│   ├── parallel_floris_model.py
│   ├── turbine_library/
│   │   ├── __init__.py
│   │   ├── demo_cp_ct_surfaces/
│   │   │   ├── iea_10MW_demo_cp_ct_surface.npz
│   │   │   ├── iea_15MW_demo_cp_ct_surface.npz
│   │   │   └── nrel_5MW_demo_cp_ct_surface.npz
│   │   ├── iea_10MW.yaml
│   │   ├── iea_15MW.yaml
│   │   ├── iea_15MW_floating_multi_dim_cp_ct.yaml
│   │   ├── iea_15MW_multi_dim_TI_u.csv
│   │   ├── iea_15MW_multi_dim_Tp_Hs.csv
│   │   ├── iea_15MW_multi_dim_cp_ct.yaml
│   │   ├── iea_22MW.yaml
│   │   ├── nrel_5MW.yaml
│   │   ├── turbine_previewer.py
│   │   └── turbine_utilities.py
│   ├── type_dec.py
│   ├── uncertain_floris_model.py
│   ├── utilities.py
│   └── wind_data.py
├── profiling/
│   ├── linux_perf.py
│   ├── profiling.py
│   ├── quality_metrics.py
│   ├── serial_vectorize.py
│   └── timing.py
├── pyproject.toml
└── tests/
    ├── __init__.py
    ├── base_unit_test.py
    ├── conftest.py
    ├── controller_dependent_operation_model_unit_test.py
    ├── convert_v3_to_v4_test.py
    ├── core_unit_test.py
    ├── data/
    │   ├── __init__.py
    │   ├── input_full.yaml
    │   ├── nrel_5MW_custom.yaml
    │   ├── wind_rose.csv
    │   ├── wind_ti_rose.csv
    │   └── wrg_test.wrg
    ├── farm_unit_test.py
    ├── floris_model_integration_test.py
    ├── flow_field_unit_test.py
    ├── geometric_yaw_unit_test.py
    ├── heterogeneous_map_integration_test.py
    ├── layout_optimization_integration_test.py
    ├── layout_visualization_test.py
    ├── load_optimization_test.py
    ├── par_floris_model_unit_test.py
    ├── parallel_floris_model_integration_test.py
    ├── reg_tests/
    │   ├── cumulative_curl_regression_test.py
    │   ├── empirical_gauss_regression_test.py
    │   ├── gauss_regression_test.py
    │   ├── jensen_jimenez_regression_test.py
    │   ├── none_regression_test.py
    │   ├── random_search_layout_opt_regression_test.py
    │   ├── scipy_layout_opt_regression.py
    │   ├── turbopark_regression_test.py
    │   ├── turboparkgauss_regression_test.py
    │   ├── turbulence_models_regression_test.py
    │   └── yaw_optimization_regression_test.py
    ├── rotor_velocity_unit_test.py
    ├── serial_refine_unit_test.py
    ├── turbine_grid_unit_test.py
    ├── turbine_multi_dim_unit_test.py
    ├── turbine_operation_models_unit_test.py
    ├── turbine_unit_test.py
    ├── turbine_utilities_unit_test.py
    ├── turboparkgauss_unit_test.py
    ├── type_dec_unit_test.py
    ├── uncertain_floris_model_integration_test.py
    ├── unified_momentum_operation_model_unit_test.py
    ├── utilities_unit_test.py
    ├── v3_to_v4_convert_test/
    │   ├── gch.yaml
    │   └── nrel_5MW_v3.yaml
    ├── wake_unit_tests.py
    ├── wind_data_integration_test.py
    ├── wind_rose_wrg_test.py
    └── yaw_optimization_integration_test.py
Download .txt
SYMBOL INDEX (1036 symbols across 114 files)

FILE: benchmarks/bench.py
  function test_timing_small_farm_set (line 19) | def test_timing_small_farm_set(benchmark):
  function test_timing_small_farm_run (line 36) | def test_timing_small_farm_run(benchmark):
  function test_timing_large_farm_set (line 54) | def test_timing_large_farm_set(benchmark):
  function test_timing_large_farm_run (line 71) | def test_timing_large_farm_run(benchmark):
  function test_timing_het_set (line 89) | def test_timing_het_set(benchmark):
  function test_timing_het_run (line 127) | def test_timing_het_run(benchmark):

FILE: examples/_convert_examples_to_notebooks.py
  function script_to_notebook (line 12) | def script_to_notebook(script_path, notebook_path):

FILE: examples/examples_emgauss/001_empirical_gauss_velocity_deficit_parameters.py
  function generate_wake_visualization (line 20) | def generate_wake_visualization(fmodel: FlorisModel, title=None):

FILE: examples/examples_emgauss/002_empirical_gauss_deflection_parameters.py
  function generate_wake_visualization (line 31) | def generate_wake_visualization(fmodel: FlorisModel, title=None):

FILE: examples/examples_get_flow/004_plot_velocity_deficit_profiles.py
  function plot_coordinate_system (line 23) | def plot_coordinate_system(x_origin, y_origin, wind_direction):
  function annotate_coordinate_system (line 37) | def annotate_coordinate_system(x_origin, y_origin, quiver_length):

FILE: examples/examples_operation_models/001_compare_yaw_loss.py
  function evaluate_yawed_power (line 36) | def evaluate_yawed_power(wsp: float, op_model: str) -> float:

FILE: examples/examples_wind_data/002_generate_ti.py
  function custom_ti_func (line 28) | def custom_ti_func(wind_directions, wind_speeds):

FILE: examples/examples_wind_data/003_generate_value.py
  function custom_value_func (line 31) | def custom_value_func(wind_directions, wind_speeds):

FILE: examples/examples_wind_resource_grid/000_generate_example_wrg.py
  function weibull_func (line 23) | def weibull_func(U, A, k):
  function estimate_weibull (line 27) | def estimate_weibull(U, freq):

FILE: floris/convert_floris_input_v3_to_v4.py
  function ignore_include (line 19) | def ignore_include(loader, node):

FILE: floris/core/base.py
  class State (line 27) | class State(Enum):
  class BaseClass (line 34) | class BaseClass(FromDictMixin):
    method logger (line 45) | def logger(self):
  class BaseModel (line 50) | class BaseModel(BaseClass):
    method prepare_function (line 60) | def prepare_function() -> dict:
    method function (line 64) | def function() -> None:

FILE: floris/core/core.py
  class Core (line 40) | class Core(BaseClass):
    method __attrs_post_init__ (line 61) | def __attrs_post_init__(self) -> None:
    method initialize_domain (line 137) | def initialize_domain(self):
    method steady_state_atmospheric_condition (line 150) | def steady_state_atmospheric_condition(self):
    method solve_for_viz (line 210) | def solve_for_viz(self):
    method solve_for_points (line 230) | def solve_for_points(self, x, y, z):
    method solve_for_velocity_deficit_profiles (line 268) | def solve_for_velocity_deficit_profiles(
    method finalize (line 343) | def finalize(self):
    method from_file (line 353) | def from_file(cls, input_file_path: str | Path) -> Core:
    method to_file (line 367) | def to_file(self, output_file_path: str) -> None:
  function check_input_file_for_v3_keys (line 381) | def check_input_file_for_v3_keys(input_dict) -> None:

FILE: floris/core/farm.py
  class Farm (line 37) | class Farm(BaseClass):
    method __attrs_post_init__ (line 124) | def __attrs_post_init__(self) -> None:
    method check_x (line 221) | def check_x(self, attribute: attrs.Attribute, value: Any) -> None:
    method check_y (line 226) | def check_y(self, attribute: attrs.Attribute, value: Any) -> None:
    method check_turbine_type (line 231) | def check_turbine_type(self, attribute: attrs.Attribute, value: Any) -...
    method check_library_path (line 241) | def check_library_path(self, attribute: attrs.Attribute, value: Path) ...
    method initialize (line 246) | def initialize(self, sorted_indices):
    method construct_hub_heights (line 280) | def construct_hub_heights(self):
    method construct_rotor_diameters (line 283) | def construct_rotor_diameters(self):
    method construct_turbine_TSRs (line 288) | def construct_turbine_TSRs(self):
    method construct_turbine_ref_tilts (line 291) | def construct_turbine_ref_tilts(self):
    method construct_turbine_correct_cp_ct_for_tilt (line 296) | def construct_turbine_correct_cp_ct_for_tilt(self):
    method construct_turbine_map (line 301) | def construct_turbine_map(self):
    method construct_turbine_thrust_coefficient_functions (line 307) | def construct_turbine_thrust_coefficient_functions(self):
    method construct_turbine_axial_induction_functions (line 312) | def construct_turbine_axial_induction_functions(self):
    method construct_turbine_tilt_interps (line 317) | def construct_turbine_tilt_interps(self):
    method construct_turbine_power_functions (line 322) | def construct_turbine_power_functions(self):
    method construct_turbine_power_thrust_tables (line 327) | def construct_turbine_power_thrust_tables(self):
    method expand_farm_properties (line 332) | def expand_farm_properties(self, n_findex: int, sorted_coord_indices):
    method set_yaw_angles (line 375) | def set_yaw_angles(self, yaw_angles: NDArrayFloat | list[float]):
    method set_yaw_angles_to_ref_yaw (line 378) | def set_yaw_angles_to_ref_yaw(self, n_findex: int):
    method set_tilt_to_ref_tilt (line 383) | def set_tilt_to_ref_tilt(self, n_findex: int):
    method set_power_setpoints (line 393) | def set_power_setpoints(self, power_setpoints: NDArrayFloat):
    method set_power_setpoints_to_ref_power (line 396) | def set_power_setpoints_to_ref_power(self, n_findex: int):
    method set_awc_modes (line 401) | def set_awc_modes(self, awc_modes: NDArrayStr):
    method set_awc_modes_to_ref_mode (line 404) | def set_awc_modes_to_ref_mode(self, n_findex: int):
    method set_awc_amplitudes (line 411) | def set_awc_amplitudes(self, awc_amplitudes: NDArrayFloat):
    method set_awc_amplitudes_to_ref_amp (line 414) | def set_awc_amplitudes_to_ref_amp(self, n_findex: int):
    method set_awc_frequencies (line 419) | def set_awc_frequencies(self, awc_frequencies: NDArrayFloat):
    method set_awc_frequencies_to_ref_freq (line 422) | def set_awc_frequencies_to_ref_freq(self, n_findex: int):
    method calculate_tilt_for_eff_velocities (line 427) | def calculate_tilt_for_eff_velocities(self, rotor_effective_velocities):
    method finalize (line 436) | def finalize(self, unsorted_indices):
    method coordinates (line 480) | def coordinates(self):
    method n_turbines (line 490) | def n_turbines(self):
  function check_turbine_definition_for_v3_keys (line 493) | def check_turbine_definition_for_v3_keys(turbine_definition: dict):

FILE: floris/core/flow_field.py
  class FlowField (line 24) | class FlowField(BaseClass):
    method turbulence_intensities_validator (line 57) | def turbulence_intensities_validator(
    method wind_directions_validator (line 74) | def wind_directions_validator(self, instance: attrs.Attribute, value: ...
    method wind_speeds_validator (line 85) | def wind_speeds_validator(self, instance: attrs.Attribute, value: NDAr...
    method heterogeneous_config_validator (line 101) | def heterogeneous_config_validator(self, instance: attrs.Attribute, va...
    method het_map_validator (line 124) | def het_map_validator(self, instance: attrs.Attribute, value: list | N...
    method __attrs_post_init__ (line 137) | def __attrs_post_init__(self) -> None:
    method initialize_velocity_field (line 142) | def initialize_velocity_field(self, grid: Grid) -> None:
    method finalize (line 241) | def finalize(self, unsorted_indices):
    method calculate_speed_ups (line 255) | def calculate_speed_ups(self, het_map, x, y, z=None):
    method generate_heterogeneous_wind_map (line 274) | def generate_heterogeneous_wind_map(self):
    method interpolate_multiplier_xy (line 350) | def interpolate_multiplier_xy(
    method interpolate_multiplier_xyz (line 378) | def interpolate_multiplier_xyz(

FILE: floris/core/grid.py
  class Grid (line 22) | class Grid(ABC, BaseClass):
    method check_coordinates (line 64) | def check_coordinates(self, instance: attrs.Attribute, value: np.ndarr...
    method wind_directions_validator (line 79) | def wind_directions_validator(self, instance: attrs.Attribute, value: ...
    method grid_resolution_validator (line 84) | def grid_resolution_validator(self, instance: attrs.Attribute, value: ...
    method set_grid (line 101) | def set_grid(self) -> None:
  class TurbineGrid (line 105) | class TurbineGrid(Grid):
    method __attrs_post_init__ (line 125) | def __attrs_post_init__(self) -> None:
    method set_grid (line 128) | def set_grid(self) -> None:
  class TurbineCubatureGrid (line 257) | class TurbineCubatureGrid(Grid):
    method __attrs_post_init__ (line 281) | def __attrs_post_init__(self) -> None:
    method set_grid (line 284) | def set_grid(self) -> None:
    method get_cubature_coefficients (line 359) | def get_cubature_coefficients(cls, N: int):
  class FlowFieldGrid (line 438) | class FlowFieldGrid(Grid):
    method __attrs_post_init__ (line 451) | def __attrs_post_init__(self) -> None:
    method set_grid (line 454) | def set_grid(self) -> None:
  class FlowFieldPlanarGrid (line 507) | class FlowFieldPlanarGrid(Grid):
    method __attrs_post_init__ (line 528) | def __attrs_post_init__(self) -> None:
    method set_grid (line 531) | def set_grid(self) -> None:
  class PointsGrid (line 621) | class PointsGrid(Grid):
    method __attrs_post_init__ (line 650) | def __attrs_post_init__(self) -> None:
    method set_grid (line 653) | def set_grid(self) -> None:

FILE: floris/core/rotor_velocity.py
  function rotor_velocity_yaw_cosine_correction (line 17) | def rotor_velocity_yaw_cosine_correction(
  function rotor_velocity_tilt_cosine_correction (line 28) | def rotor_velocity_tilt_cosine_correction(
  function simple_mean (line 54) | def simple_mean(array, axis=0):
  function cubic_mean (line 57) | def cubic_mean(array, axis=0):
  function simple_cubature (line 60) | def simple_cubature(array, cubature_weights, axis=0):
  function cubic_cubature (line 66) | def cubic_cubature(array, cubature_weights, axis=0):
  function average_velocity (line 71) | def average_velocity(
  function compute_tilt_angles_for_floating_turbines_map (line 130) | def compute_tilt_angles_for_floating_turbines_map(
  function compute_tilt_angles_for_floating_turbines (line 153) | def compute_tilt_angles_for_floating_turbines(
  function rotor_effective_velocity (line 171) | def rotor_effective_velocity(
  function rotor_velocity_air_density_correction (line 231) | def rotor_velocity_air_density_correction(

FILE: floris/core/solver.py
  function calculate_area_overlap (line 28) | def calculate_area_overlap(wake_velocities, freestream_velocities, y_ngr...
  function sequential_solver (line 45) | def sequential_solver(
  function full_flow_sequential_solver (line 258) | def full_flow_sequential_solver(
  function cc_solver (line 479) | def cc_solver(
  function full_flow_cc_solver (line 722) | def full_flow_cc_solver(
  function turbopark_solver (line 943) | def turbopark_solver(
  function full_flow_turbopark_solver (line 1180) | def full_flow_turbopark_solver(
  function empirical_gauss_solver (line 1189) | def empirical_gauss_solver(
  function full_flow_empirical_gauss_solver (line 1408) | def full_flow_empirical_gauss_solver(

FILE: floris/core/turbine/controller_dependent_operation_model.py
  class ControllerDependentTurbine (line 22) | class ControllerDependentTurbine(BaseOperationModel):
    method power (line 44) | def power(
    method thrust_coefficient (line 238) | def thrust_coefficient(
    method axial_induction (line 379) | def axial_induction(
    method compute_local_vertical_shear (line 419) | def compute_local_vertical_shear(velocities):
    method control_trajectory (line 454) | def control_trajectory(
    method find_cp (line 869) | def find_cp(sigma, cd, cl_alfa, gamma, delta, k, cosMu, sinMu, tsr, th...
    method get_ct (line 937) | def get_ct(x, *data):

FILE: floris/core/turbine/operation_models.py
  class BaseOperationModel (line 33) | class BaseOperationModel(BaseClass):
    method power (line 48) | def power() -> None:
    method thrust_coefficient (line 53) | def thrust_coefficient() -> None:
    method axial_induction (line 58) | def axial_induction() -> None:
  class SimpleTurbine (line 65) | class SimpleTurbine(BaseOperationModel):
    method power (line 75) | def power(
    method thrust_coefficient (line 109) | def thrust_coefficient(
    method axial_induction (line 138) | def axial_induction(
  class CosineLossTurbine (line 157) | class CosineLossTurbine(BaseOperationModel):
    method power (line 169) | def power(
    method thrust_coefficient (line 222) | def thrust_coefficient(
    method axial_induction (line 272) | def axial_induction(
  class SimpleDeratingTurbine (line 301) | class SimpleDeratingTurbine(BaseOperationModel):
    method power (line 310) | def power(
    method thrust_coefficient (line 334) | def thrust_coefficient(
    method axial_induction (line 362) | def axial_induction(
  class MixedOperationTurbine (line 383) | class MixedOperationTurbine(BaseOperationModel):
    method power (line 386) | def power(
    method thrust_coefficient (line 418) | def thrust_coefficient(
    method axial_induction (line 450) | def axial_induction(
    method _handle_mixed_operation_setpoints (line 482) | def _handle_mixed_operation_setpoints(
  class AWCTurbine (line 510) | class AWCTurbine(BaseOperationModel):
    method AWC_model (line 522) | def AWC_model(a, b, c, base_values, awc_amplitudes):
    method power (line 525) | def power(
    method thrust_coefficient (line 573) | def thrust_coefficient(
    method axial_induction (line 605) | def axial_induction(
  class PeakShavingTurbine (line 626) | class PeakShavingTurbine():
    method power (line 628) | def power(
    method thrust_coefficient (line 675) | def thrust_coefficient(
    method axial_induction (line 723) | def axial_induction(

FILE: floris/core/turbine/turbine.py
  function _select_multidim_condition (line 51) | def _select_multidim_condition(
  function power (line 120) | def power(
  function thrust_coefficient (line 249) | def thrust_coefficient(
  function axial_induction (line 380) | def axial_induction(
  class Turbine (line 508) | class Turbine(BaseClass):
    method __attrs_post_init__ (line 581) | def __attrs_post_init__(self) -> None:
    method __post_init__ (line 585) | def __post_init__(self) -> None:
    method _initialize_power_thrust_functions (line 622) | def _initialize_power_thrust_functions(self) -> None:
    method _initialize_tilt_interpolation (line 629) | def _initialize_tilt_interpolation(self) -> None:
    method _initialize_multidim_power_thrust_table (line 650) | def _initialize_multidim_power_thrust_table(self):
    method check_power_thrust_table (line 693) | def check_power_thrust_table(self, instance: attrs.Attribute, value: d...
    method reset_rotor_diameter_dependencies (line 724) | def reset_rotor_diameter_dependencies(self, instance: attrs.Attribute,...
    method reset_rotor_radius (line 733) | def reset_rotor_radius(self, instance: attrs.Attribute, value: float) ...
    method reset_rotor_area (line 741) | def reset_rotor_area(self, instance: attrs.Attribute, value: float) ->...
    method check_floating_tilt_table (line 749) | def check_floating_tilt_table(self, instance: attrs.Attribute, value: ...
    method check_for_cp_ct_correct_flag_if_floating (line 775) | def check_for_cp_ct_correct_flag_if_floating(

FILE: floris/core/turbine/unified_momentum_model.py
  function UMM_rotor_axial_induction (line 28) | def UMM_rotor_axial_induction(Cts: NDArrayFloat, yaw_angles: NDArrayFloa...
  function UMM_rotor_velocity_yaw_correction (line 49) | def UMM_rotor_velocity_yaw_correction(
  class FixedPointIterationCompatible (line 84) | class FixedPointIterationCompatible(Protocol):
    method residual (line 85) | def residual(self, *args, **kwargs) -> Tuple[ArrayLike]: ...
    method initial_guess (line 87) | def initial_guess(self, *args, **kwargs) -> Tuple[ArrayLike]: ...
  class FixedPointIterationResult (line 90) | class FixedPointIterationResult:
  function _fixedpointiteration (line 97) | def _fixedpointiteration(
  function fixedpointiteration (line 144) | def fixedpointiteration(
  function adaptivefixedpointiteration (line 200) | def adaptivefixedpointiteration(
  class UnifiedMomentumModelTurbine (line 246) | class UnifiedMomentumModelTurbine(BaseOperationModel):
    method power (line 251) | def power(
    method thrust_coefficient (line 308) | def thrust_coefficient(
    method axial_induction (line 359) | def axial_induction(
  class MomentumSolution (line 400) | class MomentumSolution:
    method Ct (line 416) | def Ct(self):
    method Cp (line 421) | def Cp(self):
  class LimitedHeck (line 425) | class LimitedHeck():
    method __call__ (line 431) | def __call__(self, Ctprime: float, yaw: float, **kwargs) -> MomentumSo...
  class Heck (line 452) | class Heck():
    method __init__ (line 457) | def __init__(self, v4_correction: float = 1.0):
    method initial_guess (line 472) | def initial_guess(self, Ctprime, yaw):
    method residual (line 476) | def residual(self, x: np.ndarray, Ctprime: float, yaw: float) -> np.nd...
    method post_process (line 506) | def post_process(self, result, Ctprime: float, yaw: float):

FILE: floris/core/wake.py
  class WakeModelManager (line 63) | class WakeModelManager(BaseClass):
    method __attrs_post_init__ (line 90) | def __attrs_post_init__(self) -> None:
    method validate_model_strings (line 130) | def validate_model_strings(self, instance: attrs.Attribute, value: dic...
    method deflection_function (line 151) | def deflection_function(self):
    method velocity_function (line 155) | def velocity_function(self):
    method turbulence_function (line 159) | def turbulence_function(self):
    method combination_function (line 163) | def combination_function(self):

FILE: floris/core/wake_combination/fls.py
  class FLS (line 9) | class FLS(BaseModel):
    method prepare_function (line 15) | def prepare_function(self) -> dict:
    method function (line 18) | def function(self, wake_field: np.ndarray, velocity_field: np.ndarray):

FILE: floris/core/wake_combination/max.py
  class MAX (line 9) | class MAX(BaseModel):
    method prepare_function (line 22) | def prepare_function(self) -> dict:
    method function (line 25) | def function(self, wake_field: np.ndarray, velocity_field: np.ndarray):

FILE: floris/core/wake_combination/sosfs.py
  class SOSFS (line 9) | class SOSFS(BaseModel):
    method prepare_function (line 17) | def prepare_function(self) -> dict:
    method function (line 20) | def function(self, wake_field: np.ndarray, velocity_field: np.ndarray):

FILE: floris/core/wake_deflection/empirical_gauss.py
  class EmpiricalGaussVelocityDeflection (line 18) | class EmpiricalGaussVelocityDeflection(BaseModel):
    method prepare_function (line 56) | def prepare_function(
    method function (line 68) | def function(
  function yaw_added_wake_mixing (line 130) | def yaw_added_wake_mixing(

FILE: floris/core/wake_deflection/gauss.py
  class GaussVelocityDeflection (line 25) | class GaussVelocityDeflection(BaseModel):
    method prepare_function (line 82) | def prepare_function(
    method function (line 98) | def function(
  function gamma (line 209) | def gamma(
  function wake_added_yaw (line 232) | def wake_added_yaw(
  function calculate_transverse_velocity (line 334) | def calculate_transverse_velocity(
  function yaw_added_turbulence_mixing (line 478) | def yaw_added_turbulence_mixing(

FILE: floris/core/wake_deflection/jimenez.py
  class JimenezVelocityDeflection (line 19) | class JimenezVelocityDeflection(BaseModel):
    method prepare_function (line 35) | def prepare_function(
    method function (line 47) | def function(

FILE: floris/core/wake_deflection/none.py
  class NoneVelocityDeflection (line 15) | class NoneVelocityDeflection(BaseModel):
    method prepare_function (line 21) | def prepare_function(
    method function (line 32) | def function(

FILE: floris/core/wake_turbulence/crespo_hernandez.py
  class CrespoHernandez (line 19) | class CrespoHernandez(BaseModel):
    method prepare_function (line 70) | def prepare_function(self) -> dict:
    method function (line 73) | def function(

FILE: floris/core/wake_turbulence/none.py
  class NoneWakeTurbulence (line 11) | class NoneWakeTurbulence(BaseModel):
    method prepare_function (line 17) | def prepare_function(self) -> dict:
    method function (line 20) | def function(

FILE: floris/core/wake_turbulence/wake_induced_mixing.py
  class WakeInducedMixing (line 18) | class WakeInducedMixing(BaseModel):
    method __attrs_post_init__ (line 41) | def __attrs_post_init__(self) -> None:
    method prepare_function (line 50) | def prepare_function(self) -> dict:
    method function (line 53) | def function(

FILE: floris/core/wake_velocity/cumulative_gauss_curl.py
  class CumulativeGaussCurlVelocityDeficit (line 23) | class CumulativeGaussCurlVelocityDeficit(BaseModel):
    method prepare_function (line 45) | def prepare_function(
    method function (line 59) | def function(
  function wake_expansion (line 209) | def wake_expansion(

FILE: floris/core/wake_velocity/empirical_gauss.py
  class EmpiricalGaussVelocityDeficit (line 25) | class EmpiricalGaussVelocityDeficit(BaseModel):
    method prepare_function (line 67) | def prepare_function(
    method function (line 81) | def function(
  function rCalt (line 236) | def rCalt(wind_veer, sigma_y, sigma_z, y, y_i, delta_y, delta_z, z, HH, Ct,
  function sigmoid_integral (line 259) | def sigmoid_integral(x, center=0, width=1):
  function empirical_gauss_model_wake_width (line 271) | def empirical_gauss_model_wake_width(
  function awc_added_wake_mixing (line 289) | def awc_added_wake_mixing(

FILE: floris/core/wake_velocity/gauss.py
  class GaussVelocityDeficit (line 23) | class GaussVelocityDeficit(BaseModel):
    method prepare_function (line 30) | def prepare_function(
    method function (line 46) | def function(
  function rC (line 186) | def rC(wind_veer, sigma_y, sigma_z, y, y_i, delta, z, HH, Ct, yaw, D):
  function mask_upstream_wake (line 229) | def mask_upstream_wake(mesh_y_rotated, x_coord_rotated, y_coord_rotated,...
  function gaussian_function (line 235) | def gaussian_function(C, r_squared, n, sigma):

FILE: floris/core/wake_velocity/jensen.py
  class JensenVelocityDeficit (line 24) | class JensenVelocityDeficit(BaseModel):
    method prepare_function (line 43) | def prepare_function(
    method function (line 63) | def function(

FILE: floris/core/wake_velocity/none.py
  class NoneVelocityDeficit (line 15) | class NoneVelocityDeficit(BaseModel):
    method prepare_function (line 21) | def prepare_function(
    method function (line 32) | def function(

FILE: floris/core/wake_velocity/turbopark.py
  class TurbOParkVelocityDeficit (line 27) | class TurbOParkVelocityDeficit(BaseModel):
    method __attrs_post_init__ (line 40) | def __attrs_post_init__(self) -> None:
    method prepare_function (line 53) | def prepare_function(
    method function (line 68) | def function(
  function precalculate_overlap (line 137) | def precalculate_overlap():
  function characteristic_wake_width (line 162) | def characteristic_wake_width(x_dist, TI, Cts, A):

FILE: floris/core/wake_velocity/turboparkgauss.py
  class TurboparkgaussVelocityDeficit (line 23) | class TurboparkgaussVelocityDeficit(BaseModel):
    method prepare_function (line 36) | def prepare_function(
    method function (line 52) | def function(
  function characteristic_wake_width (line 104) | def characteristic_wake_width(x_D, ambient_TI, Cts, A):

FILE: floris/cut_plane.py
  function nudge_outward (line 10) | def nudge_outward(x):
  function get_plane_from_flow_data (line 31) | def get_plane_from_flow_data(flow_data, normal_vector="z", x3_value=100):
  class CutPlane (line 88) | class CutPlane:
    method __init__ (line 94) | def __init__(self, df, x1_resolution, x2_resolution, normal_vector):
    method __sub__ (line 107) | def __sub__(self, other):
  function set_origin (line 132) | def set_origin(cut_plane, center_x1=0.0, center_x2=0.0):
  function change_resolution (line 155) | def change_resolution(cut_plane, resolution=(100, 100)):
  function interpolate_onto_array (line 225) | def interpolate_onto_array(cut_plane_in, x1_array, x2_array):
  function rescale_axis (line 295) | def rescale_axis(cut_plane, x1_factor=1.0, x2_factor=1.0):
  function project_onto (line 316) | def project_onto(cut_plane_a, cut_plane_b):
  function calculate_wind_speed (line 336) | def calculate_wind_speed(cross_plane, x1_loc, x2_loc, R):
  function wind_speed_profile (line 361) | def wind_speed_profile(cross_plane, R, x2_loc, resolution=100, x1_locs=N...
  function calculate_power (line 373) | def calculate_power(
  function get_power_profile (line 402) | def get_power_profile(

FILE: floris/floris_model.py
  class FlorisModel (line 47) | class FlorisModel(LoggingManager):
    method get_defaults (line 56) | def get_defaults() -> dict:
    method __init__ (line 65) | def __init__(self, configuration: dict | str | Path):
    method _reinitialize (line 131) | def _reinitialize(
    method set_operation (line 296) | def set_operation(
    method set (line 400) | def set(
    method reset_operation (line 504) | def reset_operation(self):
    method run (line 510) | def run(self) -> None:
    method run_no_wake (line 521) | def run_no_wake(self) -> None:
    method _get_turbine_powers (line 537) | def _get_turbine_powers(self) -> NDArrayFloat:
    method get_turbine_powers (line 573) | def get_turbine_powers(self):
    method get_expected_turbine_powers (line 609) | def get_expected_turbine_powers(self, freq=None):
    method _get_weighted_turbine_powers (line 645) | def _get_weighted_turbine_powers(
    method _get_farm_power (line 683) | def _get_farm_power(
    method get_farm_power (line 725) | def get_farm_power(
    method get_expected_farm_power (line 779) | def get_expected_farm_power(
    method get_farm_AEP (line 827) | def get_farm_AEP(
    method get_expected_farm_value (line 876) | def get_expected_farm_value(
    method get_farm_AVP (line 945) | def get_farm_AVP(
    method get_turbine_ais (line 1017) | def get_turbine_ais(self) -> NDArrayFloat:
    method get_turbine_thrust_coefficients (line 1038) | def get_turbine_thrust_coefficients(self) -> NDArrayFloat:
    method get_turbine_TIs (line 1059) | def get_turbine_TIs(self) -> NDArrayFloat:
    method set_for_viz (line 1065) | def set_for_viz(self, findex: int, solver_settings: dict) -> None:
    method calculate_cross_plane (line 1102) | def calculate_cross_plane(
    method calculate_horizontal_plane (line 1167) | def calculate_horizontal_plane(
    method calculate_y_plane (line 1238) | def calculate_y_plane(
    method get_plane_of_points (line 1305) | def get_plane_of_points(
    method sample_flow_at_points (line 1386) | def sample_flow_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: N...
    method sample_ti_at_points (line 1406) | def sample_ti_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: NDA...
    method sample_velocity_deficit_profiles (line 1425) | def sample_velocity_deficit_profiles(
    method assign_hub_height_to_ref_height (line 1552) | def assign_hub_height_to_ref_height(self):
    method get_operation_model (line 1565) | def get_operation_model(self) -> str:
    method set_operation_model (line 1580) | def set_operation_model(self, operation_model: str | List[str]):
    method copy (line 1618) | def copy(self):
    method get_param (line 1627) | def get_param(
    method set_param (line 1649) | def set_param(
    method get_turbine_layout (line 1666) | def get_turbine_layout(self, z=False):
    method show_config (line 1684) | def show_config(self, full=False) -> None:
    method print_dict (line 1699) | def print_dict(self) -> None:
    method secondary_init_kwargs (line 1711) | def secondary_init_kwargs(self):
    method layout_x (line 1719) | def layout_x(self):
    method layout_y (line 1729) | def layout_y(self):
    method wind_directions (line 1739) | def wind_directions(self):
    method wind_speeds (line 1749) | def wind_speeds(self):
    method turbulence_intensities (line 1759) | def turbulence_intensities(self):
    method n_findex (line 1769) | def n_findex(self):
    method n_turbines (line 1779) | def n_turbines(self):
    method reference_wind_height (line 1789) | def reference_wind_height(self):
    method turbine_average_velocities (line 1799) | def turbine_average_velocities(self) -> NDArrayFloat:
    method wind_data (line 1807) | def wind_data(self):
    method calculate_wake (line 1813) | def calculate_wake(self, **_):
    method reinitialize (line 1819) | def reinitialize(self, **_):
    method merge_floris_models (line 1827) | def merge_floris_models(fmodel_list, reference_wind_height=None):

FILE: floris/flow_visualization.py
  function show (line 27) | def show():
  function line_contour_cut_plane (line 36) | def line_contour_cut_plane(
  function visualize_cut_plane (line 83) | def visualize_cut_plane(
  function visualize_heterogeneous_cut_plane (line 202) | def visualize_heterogeneous_cut_plane(
  function visualize_quiver (line 276) | def visualize_quiver(cut_plane, ax=None, min_speed=None, max_speed=None,...
  function reverse_cut_plane_x_axis_in_plot (line 322) | def reverse_cut_plane_x_axis_in_plot(ax):
  function plot_rotor_values (line 332) | def plot_rotor_values(
  function calculate_horizontal_plane_with_turbines (line 419) | def calculate_horizontal_plane_with_turbines(
  class VelocityProfilesFigure (line 579) | class VelocityProfilesFigure():
    method __attrs_post_init__ (line 609) | def __attrs_post_init__(self) -> None:
    method layout_validator (line 639) | def layout_validator(self, instance : attrs.Attribute, value : list[st...
    method add_profiles (line 649) | def add_profiles(
    method match_profile_to_axes (line 667) | def match_profile_to_axes(
    method set_xlim (line 708) | def set_xlim(
    method add_ref_lines_x2 (line 715) | def add_ref_lines_x2(
    method add_ref_lines_x3 (line 736) | def add_ref_lines_x3(
    method add_ref_lines (line 757) | def add_ref_lines(

FILE: floris/heterogeneous_map.py
  class HeterogeneousMap (line 14) | class HeterogeneousMap(LoggingManager):
    method __init__ (line 44) | def __init__(
    method __str__ (line 153) | def __str__(self) -> str:
    method get_heterogeneous_inflow_config (line 179) | def get_heterogeneous_inflow_config(
    method get_heterogeneous_map_2d (line 270) | def get_heterogeneous_map_2d(self, z: float):
    method plot_heterogeneous_boundary (line 301) | def plot_heterogeneous_boundary(x, y, ax=None):
    method plot_wind_direction (line 335) | def plot_wind_direction(self, ax: plt.Axes, wind_direction: float):
    method plot_single_speed_multiplier (line 371) | def plot_single_speed_multiplier(

FILE: floris/layout_visualization.py
  function plot_turbine_points (line 20) | def plot_turbine_points(
  function plot_turbine_labels (line 85) | def plot_turbine_labels(
  function plot_turbine_rotors (line 192) | def plot_turbine_rotors(
  function get_wake_direction (line 246) | def get_wake_direction(x_i: float, y_i: float, x_j: float, y_j: float) -...
  function label_line (line 274) | def label_line(
  function plot_waking_directions (line 363) | def plot_waking_directions(
  function plot_farm_terrain (line 504) | def plot_farm_terrain(fmodel: FlorisModel, ax: plt.Axes = None) -> None:
  function shade_region (line 533) | def shade_region(

FILE: floris/logging_manager.py
  function configure_console_log (line 15) | def configure_console_log(enabled=True, level="INFO"):
  function configure_file_log (line 43) | def configure_file_log(enabled=True, level="INFO"):
  function _setup_logger (line 71) | def _setup_logger():
  class TracebackInfoFilter (line 118) | class TracebackInfoFilter(logging.Filter):
    method __init__ (line 121) | def __init__(self, clear=True):
    method filter (line 124) | def filter(self, record):
  class LoggingManager (line 133) | class LoggingManager:
    method logger (line 141) | def logger(self):

FILE: floris/optimization/layout_optimization/layout_optimization_base.py
  class LayoutOptimization (line 15) | class LayoutOptimization(LoggingManager):
    method __init__ (line 34) | def __init__(
    method __str__ (line 106) | def __str__(self):
    method _norm (line 109) | def _norm(self, val, x1, x2):
    method _unnorm (line 112) | def _unnorm(self, val, x1, x2):
    method _get_geoyaw_angles (line 115) | def _get_geoyaw_angles(self):
    method optimize (line 129) | def optimize(self):
    method plot_layout_opt_results (line 133) | def plot_layout_opt_results(
    method plot_layout_opt_boundary (line 196) | def plot_layout_opt_boundary(self, plot_boundary_dict={}, ax=None):
    method plot_progress (line 219) | def plot_progress(self, ax=None):
    method nturbs (line 268) | def nturbs(self):
    method rotor_diameter (line 280) | def rotor_diameter(self):
  function list_depth (line 285) | def list_depth(x):

FILE: floris/optimization/layout_optimization/layout_optimization_boundary_grid.py
  class LayoutOptimizationBoundaryGrid (line 14) | class LayoutOptimizationBoundaryGrid(LayoutOptimization):
    method __init__ (line 15) | def __init__(
    method _discontinuous_grid (line 50) | def _discontinuous_grid(
    method _discrete_grid (line 162) | def _discrete_grid(
    method find_lengths (line 235) | def find_lengths(self, x, y, npoints):
    method _place_boundary_turbines (line 306) | def _place_boundary_turbines(self, start, boundary_poly, nturbs=None, ...
    method _place_boundary_turbines_with_specified_spacing (line 423) | def _place_boundary_turbines_with_specified_spacing(
    method boundary_grid (line 494) | def boundary_grid(
    method reinitialize_bg (line 560) | def reinitialize_bg(
    method reinitialize_xy (line 601) | def reinitialize_xy(self):
    method plot_layout (line 617) | def plot_layout(self):
    method space_constraint (line 630) | def space_constraint(self, x, y, min_dist, rho=500):

FILE: floris/optimization/layout_optimization/layout_optimization_gridded.py
  class LayoutOptimizationGridded (line 9) | class LayoutOptimizationGridded(LayoutOptimization):
    method __init__ (line 19) | def __init__(
    method optimize (line 153) | def optimize(self):
    method _get_initial_and_final_locs (line 202) | def _get_initial_and_final_locs(self):
    method trim_to_circle (line 206) | def trim_to_circle(x_locs, y_locs, radius):

FILE: floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py
  class LayoutOptimizationPyOptSparse (line 10) | class LayoutOptimizationPyOptSparse(LayoutOptimization):
    method __init__ (line 44) | def __init__(
    method _optimize (line 112) | def _optimize(self):
    method _obj_func (line 133) | def _obj_func(self, varDict):
    method parse_opt_vars (line 162) | def parse_opt_vars(self, varDict):
    method parse_sol_vars (line 166) | def parse_sol_vars(self, sol):
    method add_var_group (line 170) | def add_var_group(self, optProb):
    method add_con_group (line 180) | def add_con_group(self, optProb):
    method compute_cons (line 186) | def compute_cons(self, funcs, x, y):
    method space_constraint (line 192) | def space_constraint(self, x, y, rho=500):
    method distance_from_boundaries (line 212) | def distance_from_boundaries(self, x, y):
    method _get_initial_and_final_locs (line 222) | def _get_initial_and_final_locs(self):
    method get_optimized_locs (line 228) | def get_optimized_locs(self):

FILE: floris/optimization/layout_optimization/layout_optimization_pyoptsparse_spread.py
  class LayoutOptimizationPyOptSparse (line 10) | class LayoutOptimizationPyOptSparse(LayoutOptimization):
    method __init__ (line 11) | def __init__(
    method _reinitialize (line 29) | def _reinitialize(self, solver=None, optOptions=None):
    method _optimize (line 64) | def _optimize(self):
    method _obj_func (line 85) | def _obj_func(self, varDict):
    method parse_opt_vars (line 111) | def parse_opt_vars(self, varDict):
    method parse_sol_vars (line 115) | def parse_sol_vars(self, sol):
    method add_var_group (line 119) | def add_var_group(self, optProb):
    method add_con_group (line 129) | def add_con_group(self, optProb):
    method compute_cons (line 135) | def compute_cons(self, funcs, x, y):
    method mean_distance (line 141) | def mean_distance(self, x, y):
    method space_constraint (line 148) | def space_constraint(self, x, y, rho=500):
    method distance_from_boundaries (line 168) | def distance_from_boundaries(self, x, y):
    method plot_layout_opt_results (line 178) | def plot_layout_opt_results(self):

FILE: floris/optimization/layout_optimization/layout_optimization_random_search.py
  function _load_local_floris_object (line 17) | def _load_local_floris_object(
  function test_min_dist (line 26) | def test_min_dist(layout_x, layout_y, min_dist):
  function test_point_in_bounds (line 31) | def test_point_in_bounds(test_x, test_y, poly_outer):
  function _get_objective (line 35) | def _get_objective(
  function _gen_dist_based_init (line 51) | def _gen_dist_based_init(
  class LayoutOptimizationRandomSearch (line 106) | class LayoutOptimizationRandomSearch(LayoutOptimization):
    method __init__ (line 107) | def __init__(
    method describe (line 319) | def describe(self):
    method _process_dist_pmf (line 327) | def _process_dist_pmf(self, dist_pmf):
    method _evaluate_opt_step (line 357) | def _evaluate_opt_step(self):
    method _generate_initial_layouts (line 418) | def _generate_initial_layouts(self):
    method _get_initial_and_final_locs (line 475) | def _get_initial_and_final_locs(self):
    method _initialize_optimization (line 482) | def _initialize_optimization(self):
    method _run_optimization_generation (line 494) | def _run_optimization_generation(self):
    method _finalize_optimization (line 550) | def _finalize_optimization(self):
    method _test_optimize (line 567) | def _test_optimize(self):
    method optimize (line 590) | def optimize(self):
    method plot_distance_pmf (line 605) | def plot_distance_pmf(self, ax=None):
  function _single_individual_opt (line 622) | def _single_individual_opt(

FILE: floris/optimization/layout_optimization/layout_optimization_scipy.py
  class LayoutOptimizationScipy (line 11) | class LayoutOptimizationScipy(LayoutOptimization):
    method __init__ (line 17) | def __init__(
    method _optimize (line 94) | def _optimize(self):
    method _obj_func (line 110) | def _obj_func(self, locs):
    method _change_coordinates (line 135) | def _change_coordinates(self, locs):
    method _generate_constraints (line 147) | def _generate_constraints(self):
    method _set_opt_bounds (line 159) | def _set_opt_bounds(self):
    method _space_constraint (line 162) | def _space_constraint(self, x_in, rho=500):
    method _distance_from_boundaries (line 191) | def _distance_from_boundaries(self, x_in):
    method _get_initial_and_final_locs (line 211) | def _get_initial_and_final_locs(self):
    method optimize (line 233) | def optimize(self):

FILE: floris/optimization/load_optimization/load_optimization.py
  function compute_lti (line 13) | def compute_lti(
  function compute_turbine_voc (line 136) | def compute_turbine_voc(
  function compute_farm_voc (line 202) | def compute_farm_voc(
  function compute_farm_revenue (line 250) | def compute_farm_revenue(
  function compute_net_revenue (line 279) | def compute_net_revenue(
  function find_A_to_satisfy_rev_voc_ratio (line 327) | def find_A_to_satisfy_rev_voc_ratio(
  function find_A_to_satisfy_target_VOC_per_MW (line 377) | def find_A_to_satisfy_target_VOC_per_MW(
  function optimize_power_setpoints (line 429) | def optimize_power_setpoints(

FILE: floris/optimization/other/boundary_grid.py
  function discontinuous_grid (line 6) | def discontinuous_grid(
  function place_boundary_turbines (line 118) | def place_boundary_turbines(n_boundary_turbs, start, boundary_x, boundar...
  function boundary_grid (line 184) | def boundary_grid(
  class BoundaryGrid (line 238) | class BoundaryGrid:
    method __init__ (line 243) | def __init__(self, fi):
    method reinitialize_bg (line 268) | def reinitialize_bg(
    method reinitialize_xy (line 315) | def reinitialize_xy(self):

FILE: floris/optimization/yaw_optimization/yaw_optimization_base.py
  class YawOptimization (line 14) | class YawOptimization(LoggingManager):
    method __init__ (line 21) | def __init__(
    method _initialize (line 185) | def _initialize(self):
    method _unpack_variable (line 193) | def _unpack_variable(self, variable, subset=False):
    method _reduce_control_problem (line 220) | def _reduce_control_problem(self):
    method _normalize_control_problem (line 286) | def _normalize_control_problem(self):
    method _calculate_farm_power (line 306) | def _calculate_farm_power(
    method _calculate_baseline_farm_power (line 377) | def _calculate_baseline_farm_power(self):
    method _finalize (line 390) | def _finalize(self, farm_power_opt_subset=None, yaw_angles_opt_subset=...
    method _verify_solutions_for_convergence (line 432) | def _verify_solutions_for_convergence(
    method _norm (line 605) | def _norm(self, val, x1, x2):
    method _unnorm (line 619) | def _unnorm(self, val_norm, x1, x2):

FILE: floris/optimization/yaw_optimization/yaw_optimization_tools.py
  function derive_downstream_turbines (line 7) | def derive_downstream_turbines(fmodel, wind_direction, wake_slope=0.30, ...

FILE: floris/optimization/yaw_optimization/yaw_optimizer_geometric.py
  class YawOptimizationGeometric (line 10) | class YawOptimizationGeometric(YawOptimization):
    method __init__ (line 20) | def __init__(
    method optimize (line 38) | def optimize(self):
  function geometric_yaw (line 69) | def geometric_yaw(
  function _process_layout (line 146) | def _process_layout(
  function _get_yaw_angles (line 187) | def _get_yaw_angles(

FILE: floris/optimization/yaw_optimization/yaw_optimizer_scipy.py
  class YawOptimizationScipy (line 8) | class YawOptimizationScipy(YawOptimization):
    method __init__ (line 16) | def __init__(
    method optimize (line 65) | def optimize(self):

FILE: floris/optimization/yaw_optimization/yaw_optimizer_sr.py
  class YawOptimizationSR (line 15) | class YawOptimizationSR(YawOptimization, LoggingManager):
    method __init__ (line 21) | def __init__(
    method _get_turbine_orders (line 101) | def _get_turbine_orders(self):
    method _calc_powers_with_memory (line 115) | def _calc_powers_with_memory(self, yaw_angles_subset, use_memory=True):
    method _generate_evaluation_grid (line 191) | def _generate_evaluation_grid(self, pass_depth, turbine_depth):
    method _process_evaluation_grid (line 237) | def _process_evaluation_grid(self):
    method optimize (line 243) | def optimize(self, print_progress=True):

FILE: floris/par_floris_model.py
  class ParFlorisModel (line 15) | class ParFlorisModel(FlorisModel):
    method __init__ (line 21) | def __init__(
    method run (line 107) | def run(self) -> None:
    method sample_flow_at_points (line 173) | def sample_flow_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: N...
    method sample_ti_at_points (line 187) | def sample_ti_at_points(self, x: NDArrayFloat, y: NDArrayFloat, z: NDA...
    method _sample_value_at_points (line 201) | def _sample_value_at_points(
    method _preprocessing (line 281) | def _preprocessing(self):
    method _postprocessing (line 346) | def _postprocessing(self):
    method _print_timings (line 383) | def _print_timings(self, t0, t1, t2, t3):
    method _get_turbine_powers (line 400) | def _get_turbine_powers(self):
    method secondary_init_kwargs (line 423) | def secondary_init_kwargs(self):
    method fmodel (line 436) | def fmodel(self):
    method interface (line 447) | def interface(self):
    method interface (line 454) | def interface(self, value):
  function _parallel_run (line 462) | def _parallel_run(fmodel_dict, set_kwargs) -> FlorisModel:
  function _parallel_run_powers_only (line 475) | def _parallel_run_powers_only(fmodel_dict, set_kwargs) -> np.ndarray:
  function _parallel_run_map (line 488) | def _parallel_run_map(x):
  function _parallel_run_powers_only_map (line 494) | def _parallel_run_powers_only_map(x):
  function _parallel_sample_flow_at_points (line 500) | def _parallel_sample_flow_at_points(fmodel_dict, set_kwargs, x, y, z):
  function _parallel_sample_flow_at_points_map (line 505) | def _parallel_sample_flow_at_points_map(x):
  function _parallel_sample_ti_at_points (line 511) | def _parallel_sample_ti_at_points(fmodel_dict, set_kwargs, x, y, z):
  function _parallel_sample_ti_at_points_map (line 516) | def _parallel_sample_ti_at_points_map(x):

FILE: floris/parallel_floris_model.py
  function _get_turbine_powers_serial (line 15) | def _get_turbine_powers_serial(fmodel_information, yaw_angles=None):
  function _get_turbine_powers_serial_no_wake (line 21) | def _get_turbine_powers_serial_no_wake(fmodel_information, yaw_angles=No...
  function _optimize_yaw_angles_serial (line 28) | def _optimize_yaw_angles_serial(
  class ParallelFlorisModel (line 58) | class ParallelFlorisModel(LoggingManager):
    method __init__ (line 59) | def __init__(
    method copy (line 159) | def copy(self):
    method set (line 165) | def set(
    method _preprocessing (line 267) | def _preprocessing(self, yaw_angles=None):
    method _merge_subsets (line 305) | def _merge_subsets(self, field, subset):
    method _postprocessing (line 310) | def _postprocessing(self, output):
    method run (line 334) | def run(self):
    method get_turbine_powers (line 340) | def get_turbine_powers(self, yaw_angles=None, no_wake=False):
    method get_farm_power (line 393) | def get_farm_power(self, yaw_angles=None, turbine_weights=None, no_wak...
    method get_farm_AEP (line 420) | def get_farm_AEP(
    method optimize_yaw_angles (line 533) | def optimize_yaw_angles(
    method get_operation_model (line 603) | def get_operation_model(self):
    method set_operation_model (line 611) | def set_operation_model(self, operation_model):
    method get_param (line 629) | def get_param(self, param, param_idx=None):
    method set_param (line 642) | def set_param(self, param, value, param_idx=None):
    method layout_x (line 665) | def layout_x(self):
    method layout_y (line 669) | def layout_y(self):
    method wind_speeds (line 673) | def wind_speeds(self):
    method wind_directions (line 677) | def wind_directions(self):
    method turbulence_intensities (line 681) | def turbulence_intensities(self):
    method n_findex (line 685) | def n_findex(self):
    method n_turbines (line 689) | def n_turbines(self):

FILE: floris/turbine_library/turbine_previewer.py
  class TurbineInterface (line 32) | class TurbineInterface:
    method from_library (line 36) | def from_library(cls, library_path: str | Path, file_name: str):
    method from_yaml (line 60) | def from_yaml(cls, file_path: str | Path):
    method from_turbine_dict (line 78) | def from_turbine_dict(cls, config_dict: dict):
    method power_curve (line 91) | def power_curve(
    method thrust_coefficient_curve (line 145) | def thrust_coefficient_curve(
    method plot_power_curve (line 204) | def plot_power_curve(
    method plot_thrust_coefficient_curve (line 274) | def plot_thrust_coefficient_curve(
  class TurbineLibrary (line 344) | class TurbineLibrary:
    method load_internal_library (line 349) | def load_internal_library(self, which: list[str] = [], exclude: list[s...
    method load_external_library (line 370) | def load_external_library(
    method compute_power_curves (line 400) | def compute_power_curves(
    method compute_thrust_coefficient_curves (line 415) | def compute_thrust_coefficient_curves(
    method plot_power_curves (line 430) | def plot_power_curves(
    method plot_thrust_coefficient_curves (line 523) | def plot_thrust_coefficient_curves(
    method plot_rotor_diameters (line 615) | def plot_rotor_diameters(
    method plot_hub_heights (line 689) | def plot_hub_heights(
    method plot_comparison (line 763) | def plot_comparison(

FILE: floris/turbine_library/turbine_utilities.py
  function build_cosine_loss_turbine_dict (line 7) | def build_cosine_loss_turbine_dict(
  function _find_nearest_value_for_wind_speed (line 174) | def _find_nearest_value_for_wind_speed(test_vals, ws_vals, ws):
  function check_smooth_power_curve (line 179) | def check_smooth_power_curve(power, tolerance=0.001):

FILE: floris/type_dec.py
  function floris_array_converter (line 32) | def floris_array_converter(data: Iterable) -> np.ndarray:
  function floris_numeric_dict_converter (line 59) | def floris_numeric_dict_converter(data: dict) -> dict:
  function _attr_serializer (line 96) | def _attr_serializer(inst: type, field: Attribute, value: Any):
  function _attr_floris_filter (line 101) | def _attr_floris_filter(inst: Attribute, value: Any) -> bool:
  function iter_validator (line 118) | def iter_validator(iter_type, item_types: Union[Any, Tuple[Any]]) -> Cal...
  function convert_to_path (line 136) | def convert_to_path(fn: str | Path) -> Path:
  class FromDictMixin (line 185) | class FromDictMixin:
    method from_dict (line 193) | def from_dict(cls, data: dict):
    method as_dict (line 233) | def as_dict(self) -> dict:

FILE: floris/uncertain_floris_model.py
  class UncertainFlorisModel (line 34) | class UncertainFlorisModel(LoggingManager):
    method __init__ (line 73) | def __init__(
    method set (line 135) | def set(
    method _set_uncertain (line 152) | def _set_uncertain(
    method reset_operation (line 238) | def reset_operation(self):
    method run (line 252) | def run(self):
    method run_no_wake (line 259) | def run_no_wake(self):
    method _get_turbine_powers (line 266) | def _get_turbine_powers(self):
    method get_turbine_powers (line 289) | def get_turbine_powers(self):
    method get_expected_turbine_powers (line 337) | def get_expected_turbine_powers(self, freq=None):
    method _get_weighted_turbine_powers (line 373) | def _get_weighted_turbine_powers(
    method _get_farm_power (line 411) | def _get_farm_power(
    method get_farm_power (line 446) | def get_farm_power(
    method get_expected_farm_power (line 500) | def get_expected_farm_power(
    method get_farm_AEP (line 550) | def get_farm_AEP(
    method get_expected_farm_value (line 601) | def get_expected_farm_value(
    method get_farm_AVP (line 670) | def get_farm_AVP(
    method _get_rounded_inputs (line 741) | def _get_rounded_inputs(
    method _expand_wind_directions (line 828) | def _expand_wind_directions(
    method _get_unique_inputs (line 902) | def _get_unique_inputs(self, input_array):
    method _get_weights (line 938) | def _get_weights(self, wd_std, wd_sample_points):
    method get_operation_model (line 960) | def get_operation_model(self) -> str:
    method set_operation_model (line 975) | def set_operation_model(self, operation_model: str | List[str]):
    method copy (line 1012) | def copy(self):
    method get_param (line 1022) | def get_param(self, param: List[str], param_idx: Optional[int] = None)...
    method set_param (line 1040) | def set_param(self, param: List[str], value: Any, param_idx: Optional[...
    method secondary_init_kwargs (line 1054) | def secondary_init_kwargs(self):
    method layout_x (line 1072) | def layout_x(self):
    method layout_y (line 1082) | def layout_y(self):
    method wind_directions (line 1092) | def wind_directions(self):
    method wind_speeds (line 1102) | def wind_speeds(self):
    method turbulence_intensities (line 1112) | def turbulence_intensities(self):
    method n_findex (line 1122) | def n_findex(self):
    method n_turbines (line 1132) | def n_turbines(self):
    method reference_wind_height (line 1142) | def reference_wind_height(self):
    method core (line 1152) | def core(self):
    method turbine_average_velocities (line 1162) | def turbine_average_velocities(self) -> NDArrayFloat:
  function map_turbine_powers_uncertain (line 1183) | def map_turbine_powers_uncertain(
  function map_turbine_values_uncertain (line 1205) | def map_turbine_values_uncertain(
  class ApproxFlorisModel (line 1255) | class ApproxFlorisModel(UncertainFlorisModel):
    method __init__ (line 1264) | def __init__(
    method secondary_init_kwargs (line 1297) | def secondary_init_kwargs(self):

FILE: floris/utilities.py
  function pshape (line 18) | def pshape(array: np.ndarray, label: str = ""):
  function cosd (line 22) | def cosd(angle):
  function sind (line 35) | def sind(angle):
  function tand (line 48) | def tand(angle):
  function wrap_180 (line 61) | def wrap_180(x):
  function wrap_360 (line 75) | def wrap_360(x):
  function check_and_identify_step_size (line 88) | def check_and_identify_step_size(wind_directions):
  function make_wind_directions_adjacent (line 150) | def make_wind_directions_adjacent(wind_directions: NDArrayFloat) -> NDAr...
  function wind_delta (line 190) | def wind_delta(wind_directions: NDArrayFloat | float):
  function rotate_coordinates_rel_west (line 218) | def rotate_coordinates_rel_west(
  function reverse_rotate_coordinates_rel_west (line 272) | def reverse_rotate_coordinates_rel_west(
  class Loader (line 329) | class Loader(yaml.SafeLoader):
    method __init__ (line 331) | def __init__(self, stream):
    method include (line 337) | def include(self, node):
  function load_yaml (line 347) | def load_yaml(filename, loader=Loader):
  function round_nearest_2_or_5 (line 352) | def round_nearest_2_or_5(x: int | float) -> int:
  function round_nearest (line 366) | def round_nearest(x: int | float, base: int = 5) -> int:
  function nested_get (line 378) | def nested_get(
  function nested_set (line 397) | def nested_set(
  function print_nested_dict (line 429) | def print_nested_dict(dictionary: Dict[str, Any], indent: int = 0) -> None:
  function is_all_scalar_dict (line 443) | def is_all_scalar_dict(dictionary: Dict[str, Any]) -> bool:

FILE: floris/wind_data.py
  class WindDataBase (line 29) | class WindDataBase:
    method unpack (line 37) | def unpack(self):
    method unpack_for_reinitialize (line 44) | def unpack_for_reinitialize(self):
    method unpack_freq (line 64) | def unpack_freq(self):
    method unpack_value (line 69) | def unpack_value(self):
    method unpack_multidim_conditions (line 74) | def unpack_multidim_conditions(self):
    method check_heterogeneous_inflow_config (line 84) | def check_heterogeneous_inflow_config(self, heterogeneous_inflow_config):
    method set_layout (line 107) | def set_layout(self, layout_x=None, layout_y=None):
  class WindRose (line 123) | class WindRose(WindDataBase):
    method __init__ (line 174) | def __init__(
    method _build_gridded_and_flattened_version (line 330) | def _build_gridded_and_flattened_version(self):
    method unpack (line 379) | def unpack(self):
    method unpack_multidim_conditions (line 420) | def unpack_multidim_conditions(self):
    method aggregate (line 430) | def aggregate(self, wd_step=None, ws_step=None, inplace=False):
    method downsample (line 437) | def downsample(self, wd_step=None, ws_step=None, inplace=False):
    method resample_by_interpolation (line 525) | def resample_by_interpolation(self, wd_step=None, ws_step=None, method...
    method upsample (line 532) | def upsample(self, wd_step=None, ws_step=None, method="linear", inplac...
    method plot (line 773) | def plot(
    method assign_ti_using_wd_ws_function (line 858) | def assign_ti_using_wd_ws_function(self, func):
    method assign_ti_using_IEC_method (line 870) | def assign_ti_using_IEC_method(self, Iref=0.07, offset=3.8):
    method plot_ti_over_ws (line 896) | def plot_ti_over_ws(
    method assign_value_using_wd_ws_function (line 930) | def assign_value_using_wd_ws_function(self, func, normalize=False):
    method assign_value_piecewise_linear (line 949) | def assign_value_piecewise_linear(
    method plot_value_over_ws (line 1000) | def plot_value_over_ws(
    method read_csv_long (line 1035) | def read_csv_long(
  class WindTIRose (line 1125) | class WindTIRose(WindDataBase):
    method __init__ (line 1175) | def __init__(
    method _build_gridded_and_flattened_version (line 1333) | def _build_gridded_and_flattened_version(self):
    method unpack (line 1380) | def unpack(self):
    method unpack_multidim_conditions (line 1421) | def unpack_multidim_conditions(self):
    method aggregate (line 1431) | def aggregate(self, wd_step=None, ws_step=None, ti_step=None, inplace=...
    method downsample (line 1438) | def downsample(self, wd_step=None, ws_step=None, ti_step=None, inplace...
    method resample_by_interpolation (line 1541) | def resample_by_interpolation(self, wd_step=None, ws_step=None, method...
    method upsample (line 1548) | def upsample(self, wd_step=None, ws_step=None, ti_step=None, method="l...
    method plot (line 1842) | def plot(
    method plot_ti_over_ws (line 1943) | def plot_ti_over_ws(
    method assign_value_using_wd_ws_ti_function (line 1981) | def assign_value_using_wd_ws_ti_function(self, func, normalize=False):
    method assign_value_piecewise_linear (line 2001) | def assign_value_piecewise_linear(
    method plot_value_over_ws (line 2052) | def plot_value_over_ws(
    method read_csv_long (line 2087) | def read_csv_long(
  class TimeSeries (line 2164) | class TimeSeries(WindDataBase):
    method __init__ (line 2213) | def __init__(
    method unpack (line 2383) | def unpack(self):
    method _wrap_wind_directions_near_360 (line 2410) | def _wrap_wind_directions_near_360(self, wind_directions, wd_step):
    method assign_ti_using_wd_ws_function (line 2429) | def assign_ti_using_wd_ws_function(self, func):
    method assign_ti_using_IEC_method (line 2440) | def assign_ti_using_IEC_method(self, Iref=0.07, offset=3.8):
    method assign_value_using_wd_ws_function (line 2466) | def assign_value_using_wd_ws_function(self, func, normalize=False):
    method assign_value_piecewise_linear (line 2483) | def assign_value_piecewise_linear(
    method to_WindRose (line 2534) | def to_WindRose(self, wd_step=2.0, ws_step=1.0, wd_edges=None, ws_edge...
    method to_WindTIRose (line 2672) | def to_WindTIRose(
  class WindRoseWRG (line 2840) | class WindRoseWRG(WindDataBase):
    method __init__ (line 2870) | def __init__(
    method read_wrg_file (line 2898) | def read_wrg_file(self, filename):
    method __str__ (line 3000) | def __str__(self) -> str:
    method _build_interpolant_function_list (line 3015) | def _build_interpolant_function_list(self, x, y, n_sectors, data):
    method _interpolate_data (line 3044) | def _interpolate_data(self, x, y, interpolant_function_list):
    method _weibull_cumulative (line 3075) | def _weibull_cumulative(self, x, a, k):
    method _generate_wind_speed_frequencies_from_weibull (line 3103) | def _generate_wind_speed_frequencies_from_weibull(self, A, k, wind_spe...
    method get_wind_rose_at_point (line 3148) | def get_wind_rose_at_point(self, x, y, wind_directions=None, wind_spee...
    method set_wd_step (line 3214) | def set_wd_step(self, wd_step):
    method set_wind_speeds (line 3229) | def set_wind_speeds(self, wind_speeds):
    method set_ti_table (line 3243) | def set_ti_table(self, ti_table):
    method set_layout (line 3257) | def set_layout(self, layout_x, layout_y):
    method _update_wind_roses (line 3284) | def _update_wind_roses(self):
    method unpack (line 3305) | def unpack(self):
    method plot_wind_roses (line 3343) | def plot_wind_roses(
    method get_heterogeneous_wind_rose (line 3375) | def get_heterogeneous_wind_rose(

FILE: profiling/linux_perf.py
  function perf (line 24) | def perf():

FILE: profiling/profiling.py
  function run_floris (line 15) | def run_floris():

FILE: profiling/quality_metrics.py
  function run_floris (line 33) | def run_floris(input_dict):
  function time_profile (line 47) | def time_profile(input_dict):
  function test_time_jensen_jimenez (line 59) | def test_time_jensen_jimenez(sample_inputs_fixture):
  function test_time_gauss (line 65) | def test_time_gauss(sample_inputs_fixture):
  function test_time_gch (line 71) | def test_time_gch(sample_inputs_fixture):
  function test_time_cumulative (line 80) | def test_time_cumulative(sample_inputs_fixture):
  function memory_profile (line 86) | def memory_profile(input_dict):
  function test_mem_jensen_jimenez (line 104) | def test_mem_jensen_jimenez(sample_inputs_fixture):

FILE: profiling/serial_vectorize.py
  function time_vec (line 12) | def time_vec(input_dict):
  function time_serial (line 26) | def time_serial(input_dict, wd, ws):

FILE: profiling/timing.py
  function time_profile (line 13) | def time_profile(input_dict):
  function internal_probe (line 20) | def internal_probe(input_dict):
  function memory_profile (line 25) | def memory_profile(input_dict):

FILE: tests/base_unit_test.py
  class ClassTest (line 10) | class ClassTest(BaseModel):
    method prepare_function (line 14) | def prepare_function() -> dict:
    method function (line 17) | def function() -> None:
  function test_get_model_values (line 21) | def test_get_model_values():
  function test_NUM_EPS (line 34) | def test_NUM_EPS():

FILE: tests/conftest.py
  function turbines_to_array (line 17) | def turbines_to_array(turbine_list: list):
  function assert_results_arrays (line 21) | def assert_results_arrays(test: np.array, baseline: np.array):
  function assert_results (line 30) | def assert_results(test: list, baseline: list):
  function print_test_values (line 40) | def print_test_values(
  function flow_field_fixture (line 148) | def flow_field_fixture(sample_inputs_fixture):
  function turbine_grid_fixture (line 153) | def turbine_grid_fixture(sample_inputs_fixture) -> TurbineGrid:
  function flow_field_grid_fixture (line 164) | def flow_field_grid_fixture(sample_inputs_fixture) -> FlowFieldGrid:
  function points_grid_fixture (line 175) | def points_grid_fixture(sample_inputs_fixture) -> PointsGrid:
  function floris_fixture (line 192) | def floris_fixture():
  function sample_inputs_fixture (line 197) | def sample_inputs_fixture():
  class SampleInputs (line 201) | class SampleInputs:
    method __init__ (line 206) | def __init__(self):

FILE: tests/controller_dependent_operation_model_unit_test.py
  function test_submodel_attributes (line 13) | def test_submodel_attributes():
  function test_ControllerDependentTurbine_power_curve (line 19) | def test_ControllerDependentTurbine_power_curve():
  function test_ControllerDependentTurbine_derating (line 65) | def test_ControllerDependentTurbine_derating():
  function test_ControllerDependentTurbine_yawing (line 113) | def test_ControllerDependentTurbine_yawing():
  function test_ControllerDependentTurbine_shear (line 152) | def test_ControllerDependentTurbine_shear():
  function test_ControllerDependentTurbine_regression (line 208) | def test_ControllerDependentTurbine_regression():
  function test_ControllerDependentTurbine_integration (line 342) | def test_ControllerDependentTurbine_integration():
  function test_CpCt_data_consistency (line 457) | def test_CpCt_data_consistency():
  function test_CpCt_warning (line 547) | def test_CpCt_warning(caplog):

FILE: tests/convert_v3_to_v4_test.py
  function test_v3_to_v4_convert (line 12) | def test_v3_to_v4_convert():

FILE: tests/core_unit_test.py
  function test_read_yaml (line 20) | def test_read_yaml():
  function test_read_dict (line 25) | def test_read_dict():
  function test_init (line 30) | def test_init():
  function test_asdict (line 37) | def test_asdict(turbine_grid_fixture: TurbineGrid):

FILE: tests/farm_unit_test.py
  function test_farm_init_homogenous_turbines (line 17) | def test_farm_init_homogenous_turbines():
  function test_asdict (line 46) | def test_asdict(sample_inputs_fixture: SampleInputs):
  function test_check_turbine_type (line 72) | def test_check_turbine_type(sample_inputs_fixture: SampleInputs):
  function test_farm_external_library (line 188) | def test_farm_external_library(sample_inputs_fixture: SampleInputs):

FILE: tests/floris_model_integration_test.py
  function test_default_init (line 21) | def test_default_init():
  function test_read_yaml (line 39) | def test_read_yaml():
  function test_assign_setpoints (line 43) | def test_assign_setpoints():
  function test_set_run (line 85) | def test_set_run():
  function test_reset_operation (line 166) | def test_reset_operation():
  function test_run_no_wake (line 192) | def test_run_no_wake():
  function test_get_turbine_powers (line 215) | def test_get_turbine_powers():
  function test_get_farm_power (line 246) | def test_get_farm_power():
  function test_disable_turbines (line 296) | def test_disable_turbines():
  function test_get_farm_aep (line 385) | def test_get_farm_aep(caplog):
  function test_expected_farm_power_regression (line 433) | def test_expected_farm_power_regression():
  function test_expected_farm_power_equals_sum_of_expected_turbine_powers (line 459) | def test_expected_farm_power_equals_sum_of_expected_turbine_powers():
  function test_expected_farm_value_regression (line 486) | def test_expected_farm_value_regression():
  function test_get_farm_avp (line 510) | def test_get_farm_avp(caplog):
  function test_set_ti (line 566) | def test_set_ti():
  function test_calculate_planes (line 595) | def test_calculate_planes(caplog):
  function test_get_turbine_powers_with_WindRose (line 635) | def test_get_turbine_powers_with_WindRose():
  function test_get_powers_with_wind_data (line 685) | def test_get_powers_with_wind_data():
  function test_get_and_set_param (line 731) | def test_get_and_set_param():
  function test_get_operation_model (line 748) | def test_get_operation_model():
  function test_set_operation_model (line 752) | def test_set_operation_model():
  function test_set_operation (line 800) | def test_set_operation():
  function test_reference_wind_height_methods (line 823) | def test_reference_wind_height_methods(caplog):
  function test_merge_floris_models (line 849) | def test_merge_floris_models():
  function test_sample_flow_at_points (line 876) | def test_sample_flow_at_points():
  function test_sample_ti_at_points (line 910) | def test_sample_ti_at_points():
  function test_set_multidim (line 943) | def test_set_multidim():

FILE: tests/flow_field_unit_test.py
  function test_n_findex (line 9) | def test_n_findex(flow_field_fixture):
  function test_initialize_velocity_field (line 13) | def test_initialize_velocity_field(flow_field_fixture, turbine_grid_fixt...
  function test_asdict (line 38) | def test_asdict(flow_field_fixture: FlowField, turbine_grid_fixture: Tur...
  function test_len_ws_equals_len_wd (line 49) | def test_len_ws_equals_len_wd(flow_field_fixture: FlowField, turbine_gri...
  function test_dim_ws_wd_ti (line 79) | def test_dim_ws_wd_ti(flow_field_fixture: FlowField, turbine_grid_fixtur...
  function test_turbulence_intensities_to_n_findex (line 106) | def test_turbulence_intensities_to_n_findex(flow_field_fixture, turbine_...

FILE: tests/geometric_yaw_unit_test.py
  function test_basic_optimization (line 24) | def test_basic_optimization(sample_inputs_fixture):
  function test_disabled_turbines (line 69) | def test_disabled_turbines(sample_inputs_fixture):
  function test_process_layout (line 120) | def test_process_layout():

FILE: tests/heterogeneous_map_integration_test.py
  function test_declare_by_parameters (line 15) | def test_declare_by_parameters():
  function test_heterogeneous_map_no_ws_no_wd (line 32) | def test_heterogeneous_map_no_ws_no_wd():
  function test_wind_direction_and_wind_speed_sizes (line 58) | def test_wind_direction_and_wind_speed_sizes():
  function test_wind_direction_and_wind_speed_unique (line 113) | def test_wind_direction_and_wind_speed_unique():
  function test_get_heterogeneous_inflow_config_by_wind_direction (line 150) | def test_get_heterogeneous_inflow_config_by_wind_direction():
  function test_get_heterogeneous_inflow_config_by_wind_speed (line 175) | def test_get_heterogeneous_inflow_config_by_wind_speed():
  function test_get_heterogeneous_inflow_config_by_wind_direction_and_wind_speed (line 200) | def test_get_heterogeneous_inflow_config_by_wind_direction_and_wind_spee...
  function test_get_heterogeneous_inflow_config_no_wind_direction_no_wind_speed (line 223) | def test_get_heterogeneous_inflow_config_no_wind_direction_no_wind_speed():
  function test_get_2d_heterogenous_map_from_3d (line 246) | def test_get_2d_heterogenous_map_from_3d():
  function test_3d_het_and_shear (line 303) | def test_3d_het_and_shear():
  function test_run_2d_het_map (line 400) | def test_run_2d_het_map(caplog):
  function test_run_2d_het_map_nearest_neighbor (line 471) | def test_run_2d_het_map_nearest_neighbor(caplog):
  function test_het_config (line 543) | def test_het_config():

FILE: tests/layout_optimization_integration_test.py
  function test_base_class (line 33) | def test_base_class(caplog):
  function test_LayoutOptimizationRandomSearch (line 79) | def test_LayoutOptimizationRandomSearch():
  function test_LayoutOptimizationGridded_initialization (line 95) | def test_LayoutOptimizationGridded_initialization(caplog):
  function test_LayoutOptimizationGridded_basic (line 123) | def test_LayoutOptimizationGridded_basic():
  function test_LayoutOptimizationGridded_diagonal (line 159) | def test_LayoutOptimizationGridded_diagonal():
  function test_LayoutOptimizationGridded_separate_boundaries (line 234) | def test_LayoutOptimizationGridded_separate_boundaries():
  function test_LayoutOptimizationGridded_hexagonal (line 259) | def test_LayoutOptimizationGridded_hexagonal():

FILE: tests/layout_visualization_test.py
  function test_get_wake_direction (line 15) | def test_get_wake_direction():
  function test_plotting_functions (line 25) | def test_plotting_functions():

FILE: tests/load_optimization_test.py
  function test_compute_lti_no_wake (line 20) | def test_compute_lti_no_wake():
  function test_compute_lti_wake (line 38) | def test_compute_lti_wake():
  function test_compute_turbine_voc_no_wake (line 51) | def test_compute_turbine_voc_no_wake():
  function test_compute_turbine_voc_wake (line 69) | def test_compute_turbine_voc_wake():
  function test_compute_net_revenue_no_wake (line 81) | def test_compute_net_revenue_no_wake():
  function test_find_A_to_satisfy_rev_voc_ratio (line 100) | def test_find_A_to_satisfy_rev_voc_ratio():
  function test_find_A_to_satisfy_target_VOC_per_MW (line 126) | def test_find_A_to_satisfy_target_VOC_per_MW():

FILE: tests/par_floris_model_unit_test.py
  function test_None_interface (line 20) | def test_None_interface(sample_inputs_fixture):
  function test_multiprocessing_interface (line 43) | def test_multiprocessing_interface(sample_inputs_fixture):
  function test_pathos_interface (line 66) | def test_pathos_interface(sample_inputs_fixture):
  function test_concurrent_interface (line 102) | def test_concurrent_interface(sample_inputs_fixture):
  function test_return_turbine_powers_only (line 138) | def test_return_turbine_powers_only(sample_inputs_fixture):
  function test_run_error (line 162) | def test_run_error(sample_inputs_fixture, caplog):
  function test_configuration_compatibility (line 187) | def test_configuration_compatibility(sample_inputs_fixture, caplog):
  function test_wind_data_objects (line 213) | def test_wind_data_objects(sample_inputs_fixture):
  function test_control_setpoints (line 265) | def test_control_setpoints(sample_inputs_fixture):
  function test_sample_flow_at_points (line 347) | def test_sample_flow_at_points(sample_inputs_fixture):
  function test_sample_ti_at_points (line 373) | def test_sample_ti_at_points(sample_inputs_fixture):
  function test_copy (line 400) | def test_copy(sample_inputs_fixture):
  function test_heterogeneous_inflow_config (line 413) | def test_heterogeneous_inflow_config(sample_inputs_fixture):
  function test_multidim_conditions (line 486) | def test_multidim_conditions(sample_inputs_fixture):

FILE: tests/parallel_floris_model_integration_test.py
  function test_raise_deprecation_warning (line 22) | def test_raise_deprecation_warning(sample_inputs_fixture, caplog):
  function test_parallel_turbine_powers (line 43) | def test_parallel_turbine_powers(sample_inputs_fixture):
  function test_parallel_get_AEP (line 76) | def test_parallel_get_AEP(sample_inputs_fixture):
  function test_parallel_uncertain_error (line 101) | def test_parallel_uncertain_error(sample_inputs_fixture):

FILE: tests/reg_tests/cumulative_curl_regression_test.py
  function test_regression_tandem (line 188) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 278) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 357) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_yaw_added_recovery (line 452) | def test_regression_yaw_added_recovery(sample_inputs_fixture):
  function test_regression_secondary_steering (line 553) | def test_regression_secondary_steering(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 653) | def test_regression_small_grid_rotation(sample_inputs_fixture):
  function test_full_flow_solver (line 726) | def test_full_flow_solver(sample_inputs_fixture):

FILE: tests/reg_tests/empirical_gauss_regression_test.py
  function test_regression_tandem (line 220) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 311) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 391) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_tilt (line 487) | def test_regression_tilt(sample_inputs_fixture):
  function test_regression_yaw_added_recovery (line 583) | def test_regression_yaw_added_recovery(sample_inputs_fixture):
  function test_regression_helix (line 768) | def test_regression_helix(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 865) | def test_regression_small_grid_rotation(sample_inputs_fixture):
  function test_full_flow_solver (line 945) | def test_full_flow_solver(sample_inputs_fixture):

FILE: tests/reg_tests/gauss_regression_test.py
  function test_regression_tandem (line 280) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 370) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 450) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_gch (line 545) | def test_regression_gch(sample_inputs_fixture):
  function test_regression_yaw_added_recovery (line 736) | def test_regression_yaw_added_recovery(sample_inputs_fixture):
  function test_regression_secondary_steering (line 837) | def test_regression_secondary_steering(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 937) | def test_regression_small_grid_rotation(sample_inputs_fixture):
  function test_full_flow_solver (line 1009) | def test_full_flow_solver(sample_inputs_fixture):

FILE: tests/reg_tests/jensen_jimenez_regression_test.py
  function test_regression_tandem (line 130) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 220) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 299) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 394) | def test_regression_small_grid_rotation(sample_inputs_fixture):
  function test_full_flow_solver (line 478) | def test_full_flow_solver(sample_inputs_fixture):

FILE: tests/reg_tests/none_regression_test.py
  function test_regression_tandem (line 131) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 221) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 300) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 318) | def test_regression_small_grid_rotation(sample_inputs_fixture):
  function test_full_flow_solver (line 391) | def test_full_flow_solver(sample_inputs_fixture):

FILE: tests/reg_tests/random_search_layout_opt_regression_test.py
  function test_random_search_layout_opt (line 35) | def test_random_search_layout_opt(sample_inputs_fixture):
  function test_random_search_layout_opt_value (line 82) | def test_random_search_layout_opt_value(sample_inputs_fixture):

FILE: tests/reg_tests/scipy_layout_opt_regression.py
  function test_scipy_layout_opt (line 33) | def test_scipy_layout_opt(sample_inputs_fixture):
  function test_scipy_layout_opt_value (line 75) | def test_scipy_layout_opt_value(sample_inputs_fixture):

FILE: tests/reg_tests/turbopark_regression_test.py
  function test_regression_tandem (line 89) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 180) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 260) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 354) | def test_regression_small_grid_rotation(sample_inputs_fixture):

FILE: tests/reg_tests/turboparkgauss_regression_test.py
  function test_regression_tandem (line 131) | def test_regression_tandem(sample_inputs_fixture):
  function test_regression_rotation (line 222) | def test_regression_rotation(sample_inputs_fixture):
  function test_regression_yaw (line 302) | def test_regression_yaw(sample_inputs_fixture):
  function test_regression_small_grid_rotation (line 396) | def test_regression_small_grid_rotation(sample_inputs_fixture):
  function test_full_flow_solver (line 464) | def test_full_flow_solver(sample_inputs_fixture):

FILE: tests/reg_tests/turbulence_models_regression_test.py
  function test_NoneWakeTurbulence (line 8) | def test_NoneWakeTurbulence(sample_inputs_fixture):

FILE: tests/reg_tests/yaw_optimization_regression_test.py
  function test_serial_refine (line 74) | def test_serial_refine(sample_inputs_fixture):
  function test_geometric_yaw (line 107) | def test_geometric_yaw(sample_inputs_fixture):
  function test_scipy_yaw_opt (line 149) | def test_scipy_yaw_opt(sample_inputs_fixture):

FILE: tests/rotor_velocity_unit_test.py
  function test_rotor_velocity_air_density_correction (line 17) | def test_rotor_velocity_air_density_correction():
  function test_rotor_velocity_yaw_cosine_correction (line 36) | def test_rotor_velocity_yaw_cosine_correction():
  function test_rotor_velocity_tilt_cosine_correction (line 75) | def test_rotor_velocity_tilt_cosine_correction():
  function test_compute_tilt_angles_for_floating_turbines (line 202) | def test_compute_tilt_angles_for_floating_turbines():
  function test_simple_cubature (line 242) | def test_simple_cubature():
  function test_cubic_cubature (line 262) | def test_cubic_cubature():

FILE: tests/serial_refine_unit_test.py
  function test_basic_optimization (line 21) | def test_basic_optimization(sample_inputs_fixture):
  function test_disabled_turbines (line 63) | def test_disabled_turbines(sample_inputs_fixture):

FILE: tests/turbine_grid_unit_test.py
  function test_set_grid (line 18) | def test_set_grid(turbine_grid_fixture):
  function test_dimensions (line 54) | def test_dimensions(turbine_grid_fixture):
  function test_dynamic_properties (line 75) | def test_dynamic_properties(turbine_grid_fixture):

FILE: tests/turbine_multi_dim_unit_test.py
  function test_turbine_init (line 50) | def test_turbine_init():
  function test_ct (line 71) | def test_ct():
  function test_power (line 148) | def test_power():
  function test_axial_induction (line 215) | def test_axial_induction():
  function test_asdict (line 275) | def test_asdict(sample_inputs_fixture: SampleInputs):
  function test_multiple_conditions (line 285) | def test_multiple_conditions():

FILE: tests/turbine_operation_models_unit_test.py
  function test_submodel_attributes (line 17) | def test_submodel_attributes():
  function test_SimpleTurbine (line 43) | def test_SimpleTurbine():
  function test_CosineLossTurbine (line 119) | def test_CosineLossTurbine():
  function test_SimpleDeratingTurbine (line 232) | def test_SimpleDeratingTurbine():
  function test_MixedOperationTurbine (line 352) | def test_MixedOperationTurbine():
  function test_AWCTurbine (line 504) | def test_AWCTurbine():
  function test_PeakShavingTurbine (line 610) | def test_PeakShavingTurbine():

FILE: tests/turbine_unit_test.py
  function test_turbine_init (line 28) | def test_turbine_init():
  function test_rotor_radius (line 67) | def test_rotor_radius():
  function test_rotor_area (line 83) | def test_rotor_area():
  function test_average_velocity (line 100) | def test_average_velocity():
  function test_ct (line 159) | def test_ct():
  function test_power (line 252) | def test_power():
  function test_axial_induction (line 371) | def test_axial_induction():
  function test_asdict (line 448) | def test_asdict(sample_inputs_fixture: SampleInputs):

FILE: tests/turbine_utilities_unit_test.py
  function test_build_turbine_dict (line 13) | def test_build_turbine_dict():
  function test_check_smooth_power_curve (line 103) | def test_check_smooth_power_curve():

FILE: tests/turboparkgauss_unit_test.py
  function test_row_of_turbines (line 12) | def test_row_of_turbines():

FILE: tests/type_dec_unit_test.py
  class AttrsDemoClass (line 19) | class AttrsDemoClass(FromDictMixin):
    method __attrs_post_init__ (line 26) | def __attrs_post_init__(self):
  function test_as_dict (line 40) | def test_as_dict():
  function test_FromDictMixin_defaults (line 47) | def test_FromDictMixin_defaults():
  function test_FromDictMixin_custom (line 64) | def test_FromDictMixin_custom():
  function test_iter_validator (line 89) | def test_iter_validator():
  function test_array_converter (line 107) | def test_array_converter():
  function test_numeric_dict_converter (line 124) | def test_numeric_dict_converter():
  function test_convert_to_path (line 163) | def test_convert_to_path():

FILE: tests/uncertain_floris_model_integration_test.py
  function test_read_yaml (line 24) | def test_read_yaml():
  function test_rounded_inputs (line 29) | def test_rounded_inputs():
  function test_expand_wind_directions (line 45) | def test_expand_wind_directions():
  function test_expand_wind_directions_with_yaw_nom (line 78) | def test_expand_wind_directions_with_yaw_nom():
  function test_get_unique_inputs (line 111) | def test_get_unique_inputs():
  function test_get_weights (line 135) | def test_get_weights():
  function test_uncertain_floris_model (line 143) | def test_uncertain_floris_model():
  function test_uncertain_floris_model_setpoints (line 176) | def test_uncertain_floris_model_setpoints():
  function test_get_powers_with_wind_data (line 228) | def test_get_powers_with_wind_data():
  function test_AEP_with_wind_data (line 275) | def test_AEP_with_wind_data():
  function test_approx_floris_model (line 303) | def test_approx_floris_model():
  function test_expected_farm_power_regression (line 340) | def test_expected_farm_power_regression():
  function test_expected_farm_power_equals_sum_of_expected_turbine_powers (line 369) | def test_expected_farm_power_equals_sum_of_expected_turbine_powers():
  function test_expected_farm_value_regression (line 396) | def test_expected_farm_value_regression():
  function test_get_and_set_param (line 423) | def test_get_and_set_param():
  function test_get_operation_model (line 438) | def test_get_operation_model():
  function test_set_operation_model (line 443) | def test_set_operation_model():
  function test_parallel_uncertain_model (line 497) | def test_parallel_uncertain_model():
  function test_copy (line 512) | def test_copy():
  function test_invalid_wd_std (line 529) | def test_invalid_wd_std():
  function test_turbine_average_velocities_shape_and_type (line 540) | def test_turbine_average_velocities_shape_and_type():
  function test_turbine_average_velocities_free_stream (line 572) | def test_turbine_average_velocities_free_stream():
  function test_turbine_average_velocities_uncertain_vs_certain (line 597) | def test_turbine_average_velocities_uncertain_vs_certain():
  function test_multidim_conditions_flag (line 633) | def test_multidim_conditions_flag(sample_inputs_fixture):
  function test_multidim_conditions (line 667) | def test_multidim_conditions(sample_inputs_fixture):

FILE: tests/unified_momentum_operation_model_unit_test.py
  function test_submodel_attributes (line 7) | def test_submodel_attributes():
  function test_UnifiedMomentumModelTurbine (line 13) | def test_UnifiedMomentumModelTurbine():

FILE: tests/utilities_unit_test.py
  function test_cosd (line 34) | def test_cosd():
  function test_sind (line 41) | def test_sind():
  function test_tand (line 48) | def test_tand():
  function test_wrap_180 (line 57) | def test_wrap_180():
  function test_wrap_360 (line 66) | def test_wrap_360():
  function test_wind_delta (line 75) | def test_wind_delta():
  function test_make_wind_directions_adjacent (line 83) | def test_make_wind_directions_adjacent():
  function test_check_and_identify_step_size (line 105) | def test_check_and_identify_step_size():
  function test_check_and_identify_step_size_value_error (line 131) | def test_check_and_identify_step_size_value_error():
  function test_rotate_coordinates_rel_west (line 144) | def test_rotate_coordinates_rel_west():
  function test_reverse_rotate_coordinates_rel_west (line 192) | def test_reverse_rotate_coordinates_rel_west():
  function test_nested_get (line 230) | def test_nested_get():
  function test_nested_set (line 242) | def test_nested_set():
  function test_is_all_scalar_dict (line 255) | def test_is_all_scalar_dict():

FILE: tests/wake_unit_tests.py
  function test_asdict (line 6) | def test_asdict(sample_inputs_fixture: SampleInputs):

FILE: tests/wind_data_integration_test.py
  class ChildClassTest (line 18) | class ChildClassTest(WindDataBase):
    method __init__ (line 19) | def __init__(self):
  function test_bad_inheritance (line 23) | def test_bad_inheritance():
  function test_time_series_instantiation (line 32) | def test_time_series_instantiation():
  function test_wind_rose_init (line 67) | def test_wind_rose_init():
  function test_wind_rose_grid (line 133) | def test_wind_rose_grid():
  function test_wind_rose_unpack (line 147) | def test_wind_rose_unpack():
  function test_unpack_for_reinitialize (line 245) | def test_unpack_for_reinitialize():
  function test_wind_rose_downsample (line 267) | def test_wind_rose_downsample():
  function test_wind_rose_upsample_directions (line 306) | def test_wind_rose_upsample_directions():
  function test_wind_rose_upsample_speeds (line 351) | def test_wind_rose_upsample_speeds():
  function test_wind_rose_upsample (line 394) | def test_wind_rose_upsample():
  function test_wind_rose_upsample_wrapping (line 460) | def test_wind_rose_upsample_wrapping():
  function test_wind_ti_rose_upsample_directions (line 491) | def test_wind_ti_rose_upsample_directions():
  function test_wind_ti_rose_upsample_speeds (line 557) | def test_wind_ti_rose_upsample_speeds():
  function test_upsample_ti_rose (line 621) | def test_upsample_ti_rose():
  function test_wrap_wind_directions_near_360 (line 701) | def test_wrap_wind_directions_near_360():
  function test_time_series_to_WindRose (line 712) | def test_time_series_to_WindRose():
  function test_time_series_to_WindRose_wrapping (line 761) | def test_time_series_to_WindRose_wrapping():
  function test_time_series_to_WindRose_with_ti (line 774) | def test_time_series_to_WindRose_with_ti():
  function test_wind_ti_rose_init (line 795) | def test_wind_ti_rose_init():
  function test_wind_ti_rose_grid (line 828) | def test_wind_ti_rose_grid():
  function test_wind_ti_rose_unpack (line 843) | def test_wind_ti_rose_unpack():
  function test_wind_ti_rose_unpack_for_reinitialize (line 972) | def test_wind_ti_rose_unpack_for_reinitialize():
  function test_wind_ti_rose_aggregate (line 1003) | def test_wind_ti_rose_aggregate():
  function test_time_series_to_WindTIRose (line 1043) | def test_time_series_to_WindTIRose():
  function test_gen_heterogeneous_inflow_config (line 1063) | def test_gen_heterogeneous_inflow_config():
  function test_heterogeneous_inflow_config_by_wd (line 1095) | def test_heterogeneous_inflow_config_by_wd():
  function test_gen_heterogeneous_inflow_config_with_wind_directions_and_wind_speeds (line 1141) | def test_gen_heterogeneous_inflow_config_with_wind_directions_and_wind_s...
  function test_gen_heterogeneous_inflow_config_with_wind_directions_and_wind_speeds_wind_rose (line 1163) | def test_gen_heterogeneous_inflow_config_with_wind_directions_and_wind_s...
  function test_read_csv_long (line 1185) | def test_read_csv_long():
  function test_read_csv_long_ti (line 1228) | def test_read_csv_long_ti():
  function test_time_series_multidim (line 1253) | def test_time_series_multidim():

FILE: tests/wind_rose_wrg_test.py
  function test_load_wrg (line 20) | def test_load_wrg():
  function test_read_header (line 24) | def test_read_header():
  function test_read_data (line 51) | def test_read_data():
  function test_build_interpolant_function_list (line 76) | def test_build_interpolant_function_list():
  function test_interpolate_data (line 114) | def test_interpolate_data():
  function test_generate_wind_speed_frequencies_from_weibull (line 136) | def test_generate_wind_speed_frequencies_from_weibull():
  function test_get_wind_rose_at_point (line 166) | def test_get_wind_rose_at_point():
  function test_wind_rose_wrg_integration (line 187) | def test_wind_rose_wrg_integration():
  function test_apply_wrg_to_floris_model (line 211) | def test_apply_wrg_to_floris_model():
  function test_apply_wrg_to_ufloris_model (line 217) | def test_apply_wrg_to_ufloris_model():

FILE: tests/yaw_optimization_integration_test.py
  function test_yaw_optimization_limits (line 13) | def test_yaw_optimization_limits(sample_inputs_fixture):
Condensed preview — 284 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,395K chars).
[
  {
    "path": ".codecov.yml",
    "chars": 426,
    "preview": "# Codecov configuration file\n\ncomment: false\n\ncoverage:\n    range: 0..100  # sets the range for the color bar in the das"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 2412,
    "preview": "---\nname: Bug report\nabout: Report a bug to help us improve\ntitle: 'Bug report'\nlabels: \"Type: Bug\"\n---\n\n<!--\nIMPORTANT "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 249,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: Usage question\n    url: https://github.com/NatLabRockies/floris/dis"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 1782,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: 'Feature request'\nlabels: 'Type: Enhancement'\n-"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 2650,
    "preview": "\n<!--\nIMPORTANT NOTES\n\nIs this pull request ready to be merged?\n- Do the existing tests pass and new tests added for new"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 305,
    "preview": "version: 2\nupdates:\n- package-ecosystem: \"pip\"\n  directory: \"/\" # Location of package manifests\n  target-branch: \"develo"
  },
  {
    "path": ".github/workflows/check-working-examples.yaml",
    "chars": 1948,
    "preview": "name: Check Examples APIs\n\non: [push, pull_request]\n\njobs:\n\n  examples-check:\n    runs-on: ${{ matrix.os }}\n    strategy"
  },
  {
    "path": ".github/workflows/continuous-integration-workflow.yaml",
    "chars": 2484,
    "preview": "name: Automated tests & code coverage\n\non: [push, pull_request]\n\njobs:\n\n  code-qa-validation:\n    runs-on: ${{ matrix.os"
  },
  {
    "path": ".github/workflows/deploy-pages.yaml",
    "chars": 2961,
    "preview": "name: deploy-pages\n\non:\n  push:\n    branches:\n    - develop\n\n\n  workflow_dispatch:  # Allows manual triggering of the wo"
  },
  {
    "path": ".github/workflows/python-publish.yml",
    "chars": 1082,
    "preview": "# This workflows will upload a Python Package using Twine when a release is created\n# Published via GitHub Actions as a "
  },
  {
    "path": ".github/workflows/quality-metrics-workflow.yaml",
    "chars": 649,
    "preview": "name: Code Quality Check\n\non: [push, pull_request]\n\njobs:\n\n  code-qa-validation:\n    runs-on: ${{ matrix.os }}\n    strat"
  },
  {
    "path": ".gitignore",
    "chars": 725,
    "preview": "\n# python compiled files\n__pycache__/\n.cache\n*.ipynb\n*.ipynb_checkpoints\n*.pyc\n*.egg-info\ndist\nbuild\n.pytest_cache\n.ruff"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 516,
    "preview": "\nrepos:\n\n- repo: https://github.com/pre-commit/pre-commit-hooks\n  rev: v4.4.0\n  hooks:\n  - id: trailing-whitespace\n  - i"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2914,
    "preview": "# Contributing to FLORIS\n\nFLORIS is a community model, and we are excited for community contributions!\nThere are a varie"
  },
  {
    "path": "LICENSE.txt",
    "chars": 1525,
    "preview": "BSD 3-Clause License\n\nCopyright (c) 2025, Alliance for Energy Innovation LLC, All rights reserved.\n\nRedistribution and u"
  },
  {
    "path": "README.md",
    "chars": 8361,
    "preview": "# FLORIS Wake Modeling and Wind Farm Controls Software\n\nFLORIS is a controls-focused wind farm simulation software incor"
  },
  {
    "path": "benchmarks/bench.py",
    "chars": 4935,
    "preview": "from pathlib import Path\n\nimport numpy as np\nimport pytest\n\nfrom floris import (\n    FlorisModel,\n    TimeSeries,\n)\nfrom"
  },
  {
    "path": "docs/.nojekyll",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/_config.yml",
    "chars": 2294,
    "preview": "# Book settings\n# Learn more at https://jupyterbook.org/customize/config.html\n\ntitle: FLORIS\nauthor: National Laboratory"
  },
  {
    "path": "docs/_toc.yml",
    "chars": 992,
    "preview": "# Table of contents\n# Learn more at https://jupyterbook.org/customize/toc.html\n\nformat: jb-book\nroot: index\nparts:\n  - c"
  },
  {
    "path": "docs/advanced_concepts.ipynb",
    "chars": 37532,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"(concepts_advanced)=\\n\",\n    \"\\n\",\n"
  },
  {
    "path": "docs/api_docs.md",
    "chars": 918,
    "preview": "# API Documentation\n\nFLORIS is primarily divided into the {py:mod}`floris` package, which contains the user-level API,\na"
  },
  {
    "path": "docs/architecture.md",
    "chars": 3862,
    "preview": "\n# Architecture and Design\n\nAt the outset of the design of the FLORIS software, a few fundamental ideas were identified\n"
  },
  {
    "path": "docs/bibliography.md",
    "chars": 53,
    "preview": "\n# Bibliography\n\n```{bibliography}\n:style: unsrt\n```\n"
  },
  {
    "path": "docs/code_quality.ipynb",
    "chars": 68447,
    "preview": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Code Qualit"
  },
  {
    "path": "docs/dev_guide.md",
    "chars": 16087,
    "preview": "# Developer's Guide\n\nFLORIS is maintained by NLR.\nWe are excited about community contribution, and this page outlines\npr"
  },
  {
    "path": "docs/empirical_gauss_model.md",
    "chars": 9460,
    "preview": "\n(empirical_gauss_model)=\n# Empirical Gaussian model\n\nFLORIS's \"empirical\" model has the same Gaussian wake shape as oth"
  },
  {
    "path": "docs/floating_wind_turbine.md",
    "chars": 1457,
    "preview": "\n# Floating Wind Turbine Modeling\n\nThe FLORIS wind turbine description includes a definition of the performance curves\n("
  },
  {
    "path": "docs/floris_models.ipynb",
    "chars": 142776,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"(floris_models)=\\n\",\n    \"\\n\",\n    "
  },
  {
    "path": "docs/heterogeneous_map.ipynb",
    "chars": 13438,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"(heterogeneous_map)=\\n\",\n    \"\\n\",\n"
  },
  {
    "path": "docs/index.md",
    "chars": 3689,
    "preview": "# FLORIS Wake Modeling & Wind Farm Controls\n\nFLORIS is a controls-focused wind farm simulation software incorporating\nst"
  },
  {
    "path": "docs/input_reference_main.md",
    "chars": 490,
    "preview": "# Main Input File Reference\n\nIn addition to calling the `set()` method on {py:class}`FlorisModel`, users can configure F"
  },
  {
    "path": "docs/input_reference_turbine.md",
    "chars": 310,
    "preview": "# Turbine Input File Reference\n\nThe turbine input file is an optional input used to define a custom turbine type.\nThe fi"
  },
  {
    "path": "docs/installation.md",
    "chars": 3860,
    "preview": "(installation)=\n# Installation\n\nFLORIS can be installed by downloading the source code or via the PyPI package manager w"
  },
  {
    "path": "docs/intro_concepts.ipynb",
    "chars": 478237,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"86e53920\",\n   \"metadata\": {},\n   \"source\": [\n    \"(intro_concept"
  },
  {
    "path": "docs/layout_optimization.md",
    "chars": 6201,
    "preview": "\n(layout_optimization)=\n# Layout Optimization\n\nThe FLORIS package provides layout optimization tools to place turbines w"
  },
  {
    "path": "docs/multidimensional_wind_turbine.ipynb",
    "chars": 6958,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"ab10767e\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Multidimensi"
  },
  {
    "path": "docs/operation_models_user.ipynb",
    "chars": 32642,
    "preview": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"id\": \"ac224ce9-bd4f-4f5c-88b7-f0e9e49ee498\",\n   "
  },
  {
    "path": "docs/references.bib",
    "chars": 14830,
    "preview": "---\n---\n\n@article{abkar2015influence,\n    title={Influence of atmospheric stability on wind-turbine wakes: A large-eddy "
  },
  {
    "path": "docs/turbine_library.md",
    "chars": 3725,
    "preview": "(turbine_library)=\n# Turbine Library\n\nFLORIS includes a library of predefined wind turbine models that can be used to qu"
  },
  {
    "path": "docs/turbine_models.ipynb",
    "chars": 5113,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"id\": \"ab10767e\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Wind turbine"
  },
  {
    "path": "docs/v3_to_v4.md",
    "chars": 10524,
    "preview": "# Switching from FLORIS v3 to v4\n\nThere are several major changes introduced in FLORIS v4. The largest underlying change"
  },
  {
    "path": "docs/wake_models.ipynb",
    "chars": 14482,
    "preview": "{\n \"cells\": [\n  {\n   \"attachments\": {},\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Wake Models"
  },
  {
    "path": "docs/wind_data_user.ipynb",
    "chars": 1301083,
    "preview": "{\n \"cells\": [\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"# Wind Data Objects\"\n   ]\n  },\n  {\n"
  },
  {
    "path": "examples/001_opening_floris_computing_power.py",
    "chars": 2607,
    "preview": "\"\"\"Example 1: Opening FLORIS and Computing Power\n\nThis example illustrates several of the key concepts in FLORIS. It dem"
  },
  {
    "path": "examples/002_visualizations.py",
    "chars": 3431,
    "preview": "\"\"\"Example 2: Visualizations\n\nThis example demonstrates the use of the flow and layout visualizations in FLORIS.\nFirst, "
  },
  {
    "path": "examples/003_wind_data_objects.py",
    "chars": 9784,
    "preview": "\"\"\"Example 3: Wind Data Objects\n\nThis example demonstrates the use of wind data objects in FLORIS:\n TimeSeries, WindRose"
  },
  {
    "path": "examples/004_set.py",
    "chars": 3344,
    "preview": "\"\"\"Example 4: Set\n\nThis example illustrates the use of the set method.  The set method is used to\nchange the wind condit"
  },
  {
    "path": "examples/005_getting_power.py",
    "chars": 4752,
    "preview": "\"\"\"Example 5: Getting Turbine and Farm Power\n\nAfter setting the FlorisModel and running, the next step is typically to g"
  },
  {
    "path": "examples/006_get_farm_aep.py",
    "chars": 2916,
    "preview": "\"\"\"Example 6: Getting Expected Power and AEP\n\nThe expected power of a farm is computed by multiplying the power output o"
  },
  {
    "path": "examples/007_sweeping_variables.py",
    "chars": 6454,
    "preview": "\"\"\"Example 7: Sweeping Variables\n\nDemonstrate methods for sweeping across variables.  Wind directions, wind speeds,\nturb"
  },
  {
    "path": "examples/008_uncertain_models.py",
    "chars": 4626,
    "preview": "\"\"\"Example 8: Uncertain Models\n\nUncertainFlorisModel is a class that adds uncertainty to the inflow wind direction\non th"
  },
  {
    "path": "examples/009_parallel_models.py",
    "chars": 3117,
    "preview": "\"\"\"Example 9: Parallel Models\n\nThis example demonstrates how to use the ParFlorisModel class to parallelize the\ncalculat"
  },
  {
    "path": "examples/010_compare_farm_power_with_neighbor.py",
    "chars": 2320,
    "preview": "\"\"\"Example 10: Compare farm power with neighboring farm\n\nThis example demonstrates how to use turbine_weights to define "
  },
  {
    "path": "examples/_convert_examples_to_notebooks.py",
    "chars": 4027,
    "preview": "\"\"\"\nUtility script to convert all Python scripts in the current directory to\n Jupyter notebooks.\n\n\"\"\"\n\nimport os\n\nimport"
  },
  {
    "path": "examples/examples_control_optimization/001_opt_yaw_single_ws.py",
    "chars": 2873,
    "preview": "\n\"\"\"Example: Optimize yaw for a single wind speed and multiple wind directions\n\nUse the serial-refine method to optimize"
  },
  {
    "path": "examples/examples_control_optimization/002_opt_yaw_single_ws_uncertain.py",
    "chars": 3236,
    "preview": "\"\"\"Example: Optimize yaw for a single wind speed and multiple wind directions.\nCompare certain and uncertain results.\n\nU"
  },
  {
    "path": "examples/examples_control_optimization/003_opt_yaw_multiple_ws.py",
    "chars": 4152,
    "preview": "\n\"\"\"Example: Optimize yaw for multiple wind directions and multiple wind speeds.\nThis example demonstrates how to perfor"
  },
  {
    "path": "examples/examples_control_optimization/004_optimize_yaw_aep.py",
    "chars": 5869,
    "preview": "\"\"\"Example: Optimize yaw and compare AEP\n\nThis example demonstrates how to perform a yaw optimization and evaluate the p"
  },
  {
    "path": "examples/examples_control_optimization/005_optimize_yaw_aep_parallel.py",
    "chars": 5091,
    "preview": "\"\"\"Example: Optimize yaw and compare AEP in parallel\n\nThis example demonstrates how to perform a yaw optimization and ev"
  },
  {
    "path": "examples/examples_control_optimization/006_compare_yaw_optimizers.py",
    "chars": 6088,
    "preview": "\n\"\"\"Example: Compare yaw optimizers\nThis example compares the SciPy-based yaw optimizer with the Serial-Refine optimizer"
  },
  {
    "path": "examples/examples_control_optimization/007_optimize_yaw_with_neighbor_farms.py",
    "chars": 11048,
    "preview": "\"\"\"Example: Optimize yaw with neighbor farm\n\nThis example demonstrates how to optimize the yaw angles of a subset of tur"
  },
  {
    "path": "examples/examples_control_optimization/008_optimize_yaw_with_disabled_turbines.py",
    "chars": 1944,
    "preview": "\"\"\"Example: Optimizing yaw angles with disabled turbines\n\nThis example demonstrates how to optimize yaw angles in FLORIS"
  },
  {
    "path": "examples/examples_control_types/001_derating_control.py",
    "chars": 2763,
    "preview": "\"\"\"Example of using the simple-derating control model in FLORIS.\n\nThis example demonstrates how to use the simple-derati"
  },
  {
    "path": "examples/examples_control_types/002_disable_turbines.py",
    "chars": 2163,
    "preview": "\"\"\"Example: Disabling turbines\n\nThis example is adapted from https://github.com/NatLabRockies/floris/pull/693\ncontribute"
  },
  {
    "path": "examples/examples_control_types/003_setting_yaw_and_disabling.py",
    "chars": 3057,
    "preview": "\"\"\"Example: Setting yaw angles and disabling turbine\n\nThis example demonstrates how to set yaw angles and disable turbin"
  },
  {
    "path": "examples/examples_control_types/004_helix_active_wake_mixing.py",
    "chars": 3612,
    "preview": "\"\"\"Example: Helix active wake mixing\n\nExample to test out using helix wake mixing of upstream turbines.\nHelix wake mixin"
  },
  {
    "path": "examples/examples_control_types/005_peak_shaving.py",
    "chars": 3111,
    "preview": "\"\"\"Example of using the peak-shaving turbine operation model.\n\nThis example demonstrates how to use the peak-shaving ope"
  },
  {
    "path": "examples/examples_emgauss/001_empirical_gauss_velocity_deficit_parameters.py",
    "chars": 5722,
    "preview": "\"\"\"Example: Empirical Gaussian velocity deficit parameters\nThis example illustrates the main parameters of the Empirical"
  },
  {
    "path": "examples/examples_emgauss/002_empirical_gauss_deflection_parameters.py",
    "chars": 6263,
    "preview": "\"\"\"Example: Empirical Gaussian deflection parameters\n\nThis example illustrates the main parameters of the Empirical Gaus"
  },
  {
    "path": "examples/examples_floating/001_floating_turbine_models.py",
    "chars": 5020,
    "preview": "\"\"\"Example: Floating turbines\nThis example demonstrates the impact of floating on turbine power and thrust (not wake beh"
  },
  {
    "path": "examples/examples_floating/002_floating_vs_fixedbottom_farm.py",
    "chars": 4407,
    "preview": "\"\"\"Example: Floating vs fixed-bottom farm\nThis example demonstrates the impact of floating on turbine power and thrust\na"
  },
  {
    "path": "examples/examples_floating/003_tilt_driven_vertical_wake_deflection.py",
    "chars": 2861,
    "preview": "\"\"\"Example: Tilt-driven vertical wake deflection\nThis example demonstrates vertical wake deflections due to the tilt ang"
  },
  {
    "path": "examples/examples_get_flow/001_extract_wind_speed_at_turbines.py",
    "chars": 1239,
    "preview": "\"\"\"Example: Extract wind speed at turbines\n\nThis example demonstrates how to extract the wind speed at the turbine point"
  },
  {
    "path": "examples/examples_get_flow/002_extract_wind_speed_at_points.py",
    "chars": 2387,
    "preview": "\"\"\"Example: Extract wind speed at points\nThis example demonstrates the use of the sample_flow_at_points method of\nFloris"
  },
  {
    "path": "examples/examples_get_flow/003_extract_turbulence_intensity_at_points.py",
    "chars": 2530,
    "preview": "\"\"\"Example: Extract turbulence intensity at points\nThis example demonstrates the use of the sample_ti_at_points method o"
  },
  {
    "path": "examples/examples_get_flow/004_plot_velocity_deficit_profiles.py",
    "chars": 8015,
    "preview": "\"\"\"Example: Plot velocity deficit profiles\n\nThis example illustrates how to plot velocity deficit profiles at several lo"
  },
  {
    "path": "examples/examples_heterogeneous/001_heterogeneous_inflow_single.py",
    "chars": 2943,
    "preview": "\"\"\"Example: Heterogeneous Inflow for single case\n\nThis example illustrates how to set up a heterogeneous inflow conditio"
  },
  {
    "path": "examples/examples_heterogeneous/002_heterogeneous_using_wind_data.py",
    "chars": 4724,
    "preview": "\"\"\"Example: Heterogeneous Inflow using wind data\n\nWhen multiple cases are considered, the heterogeneous inflow condition"
  },
  {
    "path": "examples/examples_heterogeneous/003_heterogeneous_speedup_by_wd_and_ws.py",
    "chars": 3657,
    "preview": "\"\"\"Example: Heterogeneous Speedup by Wind Direction and Wind Speed\n\nThe HeterogeneousMap object is a flexible way to def"
  },
  {
    "path": "examples/examples_heterogeneous/004_heterogeneous_2d_and_3d.py",
    "chars": 5112,
    "preview": "\"\"\"Example: Heterogeneous Inflow in 2D and 3D\n\nThis example showcases the heterogeneous inflow capabilities of FLORIS.\nH"
  },
  {
    "path": "examples/examples_layout_optimization/001_optimize_layout.py",
    "chars": 5069,
    "preview": "\n\"\"\"Example: Optimize Layout\nThis example shows a simple layout optimization using the python module Scipy, optimizing f"
  },
  {
    "path": "examples/examples_layout_optimization/002_optimize_layout_with_heterogeneity.py",
    "chars": 4867,
    "preview": "\"\"\"Example: Layout optimization with heterogeneous inflow\nThis example shows a layout optimization using the geometric y"
  },
  {
    "path": "examples/examples_layout_optimization/003_genetic_random_search.py",
    "chars": 2446,
    "preview": "\"\"\"Example: Layout optimization with genetic random search\nThis example shows a layout optimization using the genetic ra"
  },
  {
    "path": "examples/examples_layout_optimization/004_generate_gridded_layout.py",
    "chars": 1150,
    "preview": "\"\"\"Example: Gridded layout design\nThis example shows a layout optimization that places as many turbines as\npossible into"
  },
  {
    "path": "examples/examples_layout_optimization/005_layout_optimization_complex_boundary.py",
    "chars": 2594,
    "preview": "\"\"\"Example: Separated boundaries layout optimization\nDemonstrates the capabilities of LayoutOptimizationGridded and\nLayo"
  },
  {
    "path": "examples/examples_load_optimization/001_lti_and_voc.py",
    "chars": 4064,
    "preview": "\"\"\"Example: LTI and VOC Behavior with Changing Wind Direction and Power Setpoints\n\nDemonstrate the behavior of the load "
  },
  {
    "path": "examples/examples_load_optimization/002_row_opt_example.py",
    "chars": 6193,
    "preview": "\"\"\"Example: Optimize a row of turbines\n\nThis example optimizes the derating of a row of three turbines to maximize net r"
  },
  {
    "path": "examples/examples_multidim/001_multi_dimensional_cp_ct.py",
    "chars": 4495,
    "preview": "\"\"\"Example: Multi-dimensional power/thrust coefficient data\nThis example creates a FLORIS instance and:\n1) Makes a two-t"
  },
  {
    "path": "examples/examples_multidim/002_multi_dimensional_cp_ct_2Hs.py",
    "chars": 2330,
    "preview": "\"\"\"Example: Multi-dimensional power/thrust coefficient with 2 Hs values\nThis example follows the previous example but sh"
  },
  {
    "path": "examples/examples_multidim/003_multi_dimensional_cp_ct_TI.py",
    "chars": 3600,
    "preview": "\"\"\"Example: Multi-dimensional power/thrust coefficients with turbulence intensity\nThis example follows the previous exam"
  },
  {
    "path": "examples/examples_operation_models/001_compare_yaw_loss.py",
    "chars": 2377,
    "preview": "\"\"\"Example: Compare yaw loss under different operation models\n\nThis example shows demonstrates how the Controller-depend"
  },
  {
    "path": "examples/examples_turbine/001_reference_turbines.py",
    "chars": 4247,
    "preview": "\"\"\"Example: Reference turbines\n\nFor each reference wind turbine in the turbine library, make a small figure\nshowing its "
  },
  {
    "path": "examples/examples_turbine/002_multiple_turbine_types.py",
    "chars": 1285,
    "preview": "\"\"\"Example: Multiple turbine types\n\nThis example uses an input file where multiple turbine types are defined.\nThe first "
  },
  {
    "path": "examples/examples_turbine/003_specify_turbine_power_curve.py",
    "chars": 2517,
    "preview": "\"\"\"Example: Specify turbine power curve\n\nThis example demonstrates how to specify a turbine model based on a power\nand t"
  },
  {
    "path": "examples/examples_turbopark/001_compare_turbopark_implementations.py",
    "chars": 6367,
    "preview": "\"\"\"Example: Compare TurbOPark model implementations\nThis example demonstrates a new implementation of the TurbOPark mode"
  },
  {
    "path": "examples/examples_turbopark/comparison_data/Rowpark_Orsted.csv",
    "chars": 206,
    "preview": "wtg_nr,wws\r\n1,1\r\n2,0.709920677983239\r\n3,0.615355749367675\r\n4,0.551410465937128\r\n5,0.502600655337247\r\n6,0.46316755609319\r"
  },
  {
    "path": "examples/examples_turbopark/comparison_data/WindDirection_Sweep_Orsted.csv",
    "chars": 10703,
    "preview": "wd,wws\r\n240,1\r\n240.1,1\r\n240.2,1\r\n240.3,1\r\n240.4,1\r\n240.5,1\r\n240.6,1\r\n240.7,1\r\n240.8,1\r\n240.9,1\r\n241,1\r\n241.1,1\r\n241.2,1\r"
  },
  {
    "path": "examples/examples_uncertain/001_uncertain_model_params.py",
    "chars": 5049,
    "preview": "\"\"\"Example: Uncertain Model Parameters\n\nThis example demonstrates how to use the UncertainFlorisModel class to\nanalyze t"
  },
  {
    "path": "examples/examples_uncertain/002_approx_floris_model.py",
    "chars": 2109,
    "preview": "\"\"\"Example: Approximate Model Parameters\n\nThis example demonstrates how to use the UncertainFlorisModel class to\nanalyze"
  },
  {
    "path": "examples/examples_uncertain/003_uncertain_model_with_parallelization.py",
    "chars": 2626,
    "preview": "\"\"\"Example: Uncertain Model With Parallelization\n\nThis example demonstrates how to combined the parallelized model with "
  },
  {
    "path": "examples/examples_visualizations/001_layout_visualizations.py",
    "chars": 3071,
    "preview": "\"\"\"Example: Layout Visualizations\n\nDemonstrate the use of all the functions within the layout_visualization module\n\n\"\"\"\n"
  },
  {
    "path": "examples/examples_visualizations/002_visualize_y_cut_plane.py",
    "chars": 814,
    "preview": "\"\"\"Example: Visualize y cut plane\n\nDemonstrate visualizing a plane cut vertically through the flow field along the wind "
  },
  {
    "path": "examples/examples_visualizations/003_visualize_cross_plane.py",
    "chars": 822,
    "preview": "\"\"\"Example: Visualize cross plane\n\nDemonstrate visualizing a plane cut vertically through the flow field across the wind"
  },
  {
    "path": "examples/examples_visualizations/004_visualize_rotor_values.py",
    "chars": 716,
    "preview": "\"\"\"Example: Visualize rotor velocities\n\nDemonstrate visualizing the flow velocities at the rotor using plot_rotor_values"
  },
  {
    "path": "examples/examples_visualizations/005_visualize_flow_by_sweeping_turbines.py",
    "chars": 961,
    "preview": "\"\"\"Example: Visualize flow by sweeping turbines\n\nDemonstrate the use calculate_horizontal_plane_with_turbines\n\n\"\"\"\n\nimpo"
  },
  {
    "path": "examples/examples_wind_data/001_wind_data_comparisons.py",
    "chars": 4385,
    "preview": "\"\"\"Example: Wind Data Comparisons\n\nIn this example, a random time series of wind speeds, wind directions, turbulence\nint"
  },
  {
    "path": "examples/examples_wind_data/002_generate_ti.py",
    "chars": 2086,
    "preview": "\"\"\"Example: Generate TI\n\nDemonstrate usage of TI generating and plotting functionality in the WindRose\nand TimeSeries cl"
  },
  {
    "path": "examples/examples_wind_data/003_generate_value.py",
    "chars": 2655,
    "preview": "\"\"\"Example: Generate value\n\nDemonstrate usage of value generating and plotting functionality in the WindRose\nand TimeSer"
  },
  {
    "path": "examples/examples_wind_resource_grid/000_generate_example_wrg.py",
    "chars": 7167,
    "preview": "\"\"\"Example: Generate Example WRG File\n\nThis first example demonstrates the content and structure of a\nWind Resource Grid"
  },
  {
    "path": "examples/examples_wind_resource_grid/001_wind_rose_wrg.py",
    "chars": 3070,
    "preview": "\"\"\"Example: WindRoseWRG\n\n`WindRoseWRG` is a type of WindData object, like `WindRose` and `TimeSeries`, that\nis used to s"
  },
  {
    "path": "examples/examples_wind_resource_grid/002_set_floris_with_wrg.py",
    "chars": 3970,
    "preview": "\"\"\"Example: Setting FLORIS with WindRoseWRG\n\nThis example shows how to set a FLORIS model with a WindRoseWRG object.  Wh"
  },
  {
    "path": "examples/examples_wind_resource_grid/003_wrg_compar_layout_optimization.py",
    "chars": 7826,
    "preview": "\"\"\"Example: Layout optimization with WindRoseWRG comparison\n\nThis example compares a layout optimization using a WindRos"
  },
  {
    "path": "examples/examples_wind_resource_grid/wrg_example.wrg",
    "chars": 1393,
    "preview": "2 3 0.0 0.0 1000.0\n                   0         0       0   90  9.5  2.25              0 12 116 106  273  86  93  228  6"
  },
  {
    "path": "examples/inputs/cc.yaml",
    "chars": 1512,
    "preview": "\nname: CC\ndescription: Three turbines using Cumulative Gauss Curl model\nfloris_version: v4\n\nlogging:\n  console:\n    enab"
  },
  {
    "path": "examples/inputs/emgauss.yaml",
    "chars": 1990,
    "preview": "\nname: Emperical Gaussian\ndescription: Three turbines using emperical Gaussian model\nfloris_version: v4\n\nlogging:\n  cons"
  },
  {
    "path": "examples/inputs/emgauss_helix.yaml",
    "chars": 2048,
    "preview": "\nname: Emperical Gaussian\ndescription: Three turbines using empirical Gaussian model\nfloris_version: v4.0\n\nlogging:\n  co"
  },
  {
    "path": "examples/inputs/gch.yaml",
    "chars": 7113,
    "preview": "\n###\n# Name for the input file.\n# This is not used by FLORIS and is simply for the user's reference.\n# String type.\nname"
  },
  {
    "path": "examples/inputs/gch_heterogeneous_inflow.yaml",
    "chars": 1705,
    "preview": "name: GCH\ndescription: Three turbines using Gauss Curl Hybrid model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: "
  },
  {
    "path": "examples/inputs/gch_multi_dim_cp_ct.yaml",
    "chars": 2108,
    "preview": "\nname: GCH multi dimensional power/thrust coefficient\ndescription: Three turbines using GCH model\nfloris_version: v4\n\nlo"
  },
  {
    "path": "examples/inputs/gch_multi_dim_cp_ct_TI.yaml",
    "chars": 2138,
    "preview": "\nname: GCH multi dimensional power/thrust coefficient\ndescription: Three turbines using GCH model\nfloris_version: v4\n\nlo"
  },
  {
    "path": "examples/inputs/gch_multiple_turbine_types.yaml",
    "chars": 1558,
    "preview": "\nname: GCH\ndescription: Three turbines using Gauss Curl Hybrid model\nfloris_version: v4\n\nlogging:\n  console:\n    enable:"
  },
  {
    "path": "examples/inputs/jensen.yaml",
    "chars": 1527,
    "preview": "\nname: Jensen-Jimenez\ndescription: Three turbines using Jensen / Jimenez models\nfloris_version: v4\n\nlogging:\n  console:\n"
  },
  {
    "path": "examples/inputs/turbine_files/iea_15MW_multi_dim_TI.csv",
    "chars": 4111,
    "preview": "TI,ws,power,thrust_coefficient\n0.06,0.0,0.0,0.0\n0.06,2.9,0.0,0.0\n0.06,3.0,42.733312,0.80742173\n0.06,3.54953237,292.58598"
  },
  {
    "path": "examples/inputs/turbine_files/iea_15MW_multi_dim_TI.yaml",
    "chars": 413,
    "preview": "turbine_type: 'iea_15MW_floating'\nhub_height: 150.0\nrotor_diameter: 242.24\nTSR: 8.0\nmulti_dimensional_cp_ct: True\npower_"
  },
  {
    "path": "examples/inputs/turbopark.yaml",
    "chars": 1534,
    "preview": "\nname: TurbOPark\ndescription: Three turbines using TurbOPark model\nfloris_version: v4\n\nlogging:\n  console:\n    enable: f"
  },
  {
    "path": "examples/inputs/turbopark_cubature.yaml",
    "chars": 1470,
    "preview": "name: Case TwinPark FLORIS v4.0\ndescription: Two aligned wind turbines with 5D spacing as currently implemented in v4.0\n"
  },
  {
    "path": "examples/inputs/turboparkgauss.yaml",
    "chars": 1122,
    "preview": "\nname: TurbOParkGauss\ndescription: Three turbines using TurbOParkGauss model\nfloris_version: v4\n\nlogging:\n  console:\n   "
  },
  {
    "path": "examples/inputs/turboparkgauss_cubature.yaml",
    "chars": 1534,
    "preview": "name: Case TwinPark new implementation\ndescription: Two aligned wind turbines with 5D spacing under the new implementati"
  },
  {
    "path": "examples/inputs/wind_rose.csv",
    "chars": 50708,
    "preview": "ws,wd,freq_val\n0.0,0.0,1.629513753096076e-05\n0.0,5.0,1.629513753096076e-05\n0.0,10.0,4.888541259288228e-05\n0.0,15.0,3.259"
  },
  {
    "path": "examples/inputs_floating/emgauss_fixed.yaml",
    "chars": 2017,
    "preview": "\nname: Emperical Gaussian\ndescription: Example of single fixed-bottom turbine\nfloris_version: v4\n\nlogging:\n  console:\n  "
  },
  {
    "path": "examples/inputs_floating/emgauss_floating.yaml",
    "chars": 2016,
    "preview": "\nname: Emperical Gaussian\ndescription: Example of single floating turbine\nfloris_version: v4\n\nlogging:\n  console:\n    en"
  },
  {
    "path": "examples/inputs_floating/emgauss_floating_fixedtilt15.yaml",
    "chars": 2024,
    "preview": "\nname: Emperical Gaussian floating\ndescription: Single turbine using emperical Gaussian model for floating\nfloris_versio"
  },
  {
    "path": "examples/inputs_floating/emgauss_floating_fixedtilt5.yaml",
    "chars": 2023,
    "preview": "\nname: Emperical Gaussian floating\ndescription: Single turbine using emperical Gaussian model for floating\nfloris_versio"
  },
  {
    "path": "examples/inputs_floating/gch_fixed.yaml",
    "chars": 1465,
    "preview": "\nname: GCH\ndescription: Example of single fixed-bottom turbine\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n"
  },
  {
    "path": "examples/inputs_floating/gch_floating.yaml",
    "chars": 1465,
    "preview": "\n\nname: GCH\ndescription: Example of single floating turbine\nfloris_version: v4\n\nlogging:\n  console:\n    enable: true\n   "
  },
  {
    "path": "examples/inputs_floating/gch_floating_defined_floating.yaml",
    "chars": 1539,
    "preview": "\nname: GCH\ndescription: Example of single floating turbine where the cp/ct is calculated with floating tilt included\nflo"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_fixed.yaml",
    "chars": 3025,
    "preview": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply "
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating.yaml",
    "chars": 3025,
    "preview": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply "
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating_defined_floating.yaml",
    "chars": 3033,
    "preview": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: False # Do no"
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating_fixedtilt15.yaml",
    "chars": 3030,
    "preview": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply "
  },
  {
    "path": "examples/inputs_floating/turbine_files/nrel_5MW_floating_fixedtilt5.yaml",
    "chars": 3025,
    "preview": "turbine_type: 'nrel_5MW_floating'\nhub_height: 90.0\nrotor_diameter: 125.88\nTSR: 8.0\ncorrect_cp_ct_for_tilt: True # Apply "
  },
  {
    "path": "floris/__init__.py",
    "chars": 559,
    "preview": "\nfrom importlib.metadata import version\nfrom pathlib import Path\n\n\n__version__ = version(\"floris\")\n\n\nfrom .floris_model "
  },
  {
    "path": "floris/convert_floris_input_v3_to_v4.py",
    "chars": 3754,
    "preview": "import sys\nfrom pathlib import Path\n\nimport yaml\n\n\n\"\"\"\nThis script is intended to be called with an argument and convert"
  },
  {
    "path": "floris/convert_turbine_v3_to_v4.py",
    "chars": 3067,
    "preview": "\nimport sys\nfrom pathlib import Path\n\nfrom floris.turbine_library import build_cosine_loss_turbine_dict, check_smooth_po"
  },
  {
    "path": "floris/core/__init__.py",
    "chars": 1523,
    "preview": "\n\"\"\"\nThe :py:obj:`floris` package contains :py:obj:`floris.utilities` module\nand the modules that make up the FLORIS sof"
  },
  {
    "path": "floris/core/base.py",
    "chars": 1562,
    "preview": "\nfrom abc import abstractmethod\nfrom enum import Enum\nfrom typing import (\n    Any,\n    Dict,\n    Final,\n)\n\nfrom attrs i"
  },
  {
    "path": "floris/core/core.py",
    "chars": 16318,
    "preview": "from __future__ import annotations\n\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\nimport yaml\nfrom at"
  },
  {
    "path": "floris/core/farm.py",
    "chars": 21906,
    "preview": "import copy\nfrom collections.abc import Callable\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    Dict,\n    Li"
  },
  {
    "path": "floris/core/flow_field.py",
    "chars": 17772,
    "preview": "import copy\n\nimport attrs\nimport matplotlib.path as mpltPath\nimport numpy as np\nfrom attrs import define, field\nfrom sci"
  },
  {
    "path": "floris/core/grid.py",
    "chars": 35611,
    "preview": "from abc import ABC, abstractmethod\nfrom typing import Iterable\n\nimport attrs\nimport numpy as np\nfrom attrs import defin"
  },
  {
    "path": "floris/core/rotor_velocity.py",
    "chars": 9008,
    "preview": "import copy\nfrom collections.abc import Iterable\n\nimport numpy as np\nfrom scipy.interpolate import interp1d\n\nfrom floris"
  },
  {
    "path": "floris/core/solver.py",
    "chars": 66810,
    "preview": "import copy\n\nimport numpy as np\n\nfrom floris.core import (\n    axial_induction,\n    Farm,\n    FlowField,\n    FlowFieldGr"
  },
  {
    "path": "floris/core/turbine/__init__.py",
    "chars": 369,
    "preview": "\nfrom floris.core.turbine.controller_dependent_operation_model import ControllerDependentTurbine\nfrom floris.core.turbin"
  },
  {
    "path": "floris/core/turbine/controller_dependent_operation_model.py",
    "chars": 36169,
    "preview": "import copy\n\nimport numpy as np\nfrom attrs import define\nfrom scipy.interpolate import RegularGridInterpolator\nfrom scip"
  },
  {
    "path": "floris/core/turbine/operation_models.py",
    "chars": 27108,
    "preview": "import copy\nfrom abc import abstractmethod\nfrom typing import (\n    Any,\n    Dict,\n    Final,\n)\n\nimport numpy as np\nfrom"
  },
  {
    "path": "floris/core/turbine/turbine.py",
    "chars": 34565,
    "preview": "import copy\nimport logging\nimport os\nfrom collections.abc import Callable, Iterable\nfrom pathlib import Path\n\nimport att"
  },
  {
    "path": "floris/core/turbine/unified_momentum_model.py",
    "chars": 17089,
    "preview": "from dataclasses import dataclass\nfrom typing import (\n    Any,\n    Callable,\n    List,\n    Optional,\n    Protocol,\n    "
  },
  {
    "path": "floris/core/wake.py",
    "chars": 5899,
    "preview": "\nimport attrs\nfrom attrs import define, field\n\nfrom floris.core import BaseClass, BaseModel\nfrom floris.core.wake_combin"
  },
  {
    "path": "floris/core/wake_combination/__init__.py",
    "chars": 152,
    "preview": "\nfrom floris.core.wake_combination.fls import FLS\nfrom floris.core.wake_combination.max import MAX\nfrom floris.core.wake"
  },
  {
    "path": "floris/core/wake_combination/fls.py",
    "chars": 893,
    "preview": "\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import BaseModel\n\n\n@define\nclass FLS(BaseModel):\n    \"\"\"\n"
  },
  {
    "path": "floris/core/wake_combination/max.py",
    "chars": 1029,
    "preview": "\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import BaseModel\n\n\n@define\nclass MAX(BaseModel):\n    \"\"\"\n"
  },
  {
    "path": "floris/core/wake_combination/sosfs.py",
    "chars": 871,
    "preview": "\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import BaseModel\n\n\n@define\nclass SOSFS(BaseModel):\n    \"\""
  },
  {
    "path": "floris/core/wake_deflection/__init__.py",
    "chars": 302,
    "preview": "\nfrom floris.core.wake_deflection.empirical_gauss import EmpiricalGaussVelocityDeflection\nfrom floris.core.wake_deflecti"
  },
  {
    "path": "floris/core/wake_deflection/empirical_gauss.py",
    "chars": 4928,
    "preview": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseMod"
  },
  {
    "path": "floris/core/wake_deflection/gauss.py",
    "chars": 17715,
    "preview": "from typing import Any\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import (\n    define,\n    field,\n    fields,\n)"
  },
  {
    "path": "floris/core/wake_deflection/jimenez.py",
    "chars": 4101,
    "preview": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core"
  },
  {
    "path": "floris/core/wake_deflection/none.py",
    "chars": 1461,
    "preview": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define\n\nfrom floris.core import (\n    BaseModel,\n   "
  },
  {
    "path": "floris/core/wake_turbulence/__init__.py",
    "chars": 216,
    "preview": "\nfrom floris.core.wake_turbulence.crespo_hernandez import CrespoHernandez\nfrom floris.core.wake_turbulence.none import N"
  },
  {
    "path": "floris/core/wake_turbulence/crespo_hernandez.py",
    "chars": 3933,
    "preview": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core"
  },
  {
    "path": "floris/core/wake_turbulence/none.py",
    "chars": 788,
    "preview": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import BaseModel\n\n\n@"
  },
  {
    "path": "floris/core/wake_turbulence/wake_induced_mixing.py",
    "chars": 2507,
    "preview": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseMod"
  },
  {
    "path": "floris/core/wake_velocity/__init__.py",
    "chars": 531,
    "preview": "\nfrom floris.core.wake_velocity.cumulative_gauss_curl import CumulativeGaussCurlVelocityDeficit\nfrom floris.core.wake_ve"
  },
  {
    "path": "floris/core/wake_velocity/cumulative_gauss_curl.py",
    "chars": 6767,
    "preview": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\nfrom scipy.special import gamma\n\nfrom "
  },
  {
    "path": "floris/core/wake_velocity/empirical_gauss.py",
    "chars": 10927,
    "preview": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core"
  },
  {
    "path": "floris/core/wake_velocity/gauss.py",
    "chars": 8334,
    "preview": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core"
  },
  {
    "path": "floris/core/wake_velocity/jensen.py",
    "chars": 4188,
    "preview": "\nfrom typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import (\n    define,\n    field,\n    fi"
  },
  {
    "path": "floris/core/wake_velocity/none.py",
    "chars": 1263,
    "preview": "\nfrom typing import Any, Dict\n\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core import (\n    BaseMod"
  },
  {
    "path": "floris/core/wake_velocity/turbopark.py",
    "chars": 6383,
    "preview": "\n\nfrom pathlib import Path\nfrom typing import Any, Dict\n\nimport numpy as np\nimport scipy.io\nfrom attrs import define, fi"
  },
  {
    "path": "floris/core/wake_velocity/turboparkgauss.py",
    "chars": 4052,
    "preview": "from typing import Any, Dict\n\nimport numexpr as ne\nimport numpy as np\nfrom attrs import define, field\n\nfrom floris.core "
  },
  {
    "path": "floris/cut_plane.py",
    "chars": 13916,
    "preview": "\nimport copy\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom scipy.interpolate import gridd"
  },
  {
    "path": "floris/default_inputs.yaml",
    "chars": 2027,
    "preview": "\nname: GCH\ndescription: \"Default initialization: Gauss-Curl hybrid model (GCH)\"\nfloris_version: v4\n\nlogging:\n  console:\n"
  },
  {
    "path": "floris/floris_model.py",
    "chars": 81144,
    "preview": "import copy\nimport inspect\nfrom pathlib import Path\nfrom typing import (\n    Any,\n    List,\n    Optional,\n)\n\nimport nump"
  },
  {
    "path": "floris/flow_visualization.py",
    "chars": 27835,
    "preview": "import copy\nimport warnings\nfrom typing import Union\n\nimport attrs\nimport matplotlib as mpl\nimport matplotlib.colors as "
  },
  {
    "path": "floris/heterogeneous_map.py",
    "chars": 22303,
    "preview": "import matplotlib.cm as cm\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport scipy.spatial._"
  },
  {
    "path": "floris/layout_visualization.py",
    "chars": 21418,
    "preview": "\nimport math\nfrom typing import (\n    Any,\n    Dict,\n    List,\n    Tuple,\n)\n\nimport matplotlib.lines\nimport matplotlib.p"
  },
  {
    "path": "floris/logging_manager.py",
    "chars": 4499,
    "preview": "\nimport logging\nfrom datetime import datetime\n\nimport coloredlogs\n\n\n# Global variables for logging\nLOG_TO_CONSOLE = True"
  },
  {
    "path": "floris/optimization/__init__.py",
    "chars": 76,
    "preview": "from . import (\n    layout_optimization,\n    other,\n    yaw_optimization,\n)\n"
  },
  {
    "path": "floris/optimization/layout_optimization/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_base.py",
    "chars": 10124,
    "preview": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom shapely.geometry import MultiPolygon, Polygon\n\nfrom floris impo"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_boundary_grid.py",
    "chars": 23715,
    "preview": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry impor"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_gridded.py",
    "chars": 9847,
    "preview": "import numpy as np\n\nfrom floris import FlorisModel\n\nfrom .layout_optimization_base import LayoutOptimization\nfrom .layou"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_pyoptsparse.py",
    "chars": 9015,
    "preview": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry impor"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_pyoptsparse_spread.py",
    "chars": 7230,
    "preview": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.spatial.distance import cdist\nfrom shapely.geometry impor"
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_random_search.py",
    "chars": 27680,
    "preview": "from multiprocessing import Pool\nfrom time import perf_counter as timerpc\n\nimport matplotlib.pyplot as plt\nimport numpy "
  },
  {
    "path": "floris/optimization/layout_optimization/layout_optimization_scipy.py",
    "chars": 8966,
    "preview": "\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.optimize import minimize\nfrom scipy.spatial.distance impo"
  },
  {
    "path": "floris/optimization/load_optimization/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "floris/optimization/load_optimization/load_optimization.py",
    "chars": 20423,
    "preview": "\"\"\"Module for the load optimization class and functions.\"\"\"\n\nimport numpy as np\n\nfrom floris import FlorisModel\nfrom flo"
  },
  {
    "path": "floris/optimization/other/__init__.py",
    "chars": 28,
    "preview": "from . import boundary_grid\n"
  },
  {
    "path": "floris/optimization/other/boundary_grid.py",
    "chars": 12797,
    "preview": "\nimport numpy as np\nfrom shapely.geometry import Point, Polygon\n\n\ndef discontinuous_grid(\n    nrows,\n    ncols,\n    farm"
  }
]

// ... and 84 more files (download for full content)

About this extraction

This page contains the full source code of the NREL/floris GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 284 files (4.1 MB), approximately 1.1M tokens, and a symbol index with 1036 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!